<commit_before>use bson::Bson;
use std::collections::BTreeMap;
use std::iter::{FromIterator, Map};

/// A BSON document represented as an associative BTree Map with insertion ordering.
#[derive(Debug, Clone)]
pub struct OrderedDocument {
    pub keys: Vec<String>,
    document: BTreeMap<String, Bson>,
}

/// An iterator over OrderedDocument entries.
#[derive(Clone)]
pub struct OrderedDocumentIterator {
    ordered_document: OrderedDocument,
    index: usize,
}

/// An owning iterator over OrderedDocument entries.
#[derive(Clone)]
pub struct OrderedDocumentIntoIterator<'a> {
    ordered_document: &'a OrderedDocument,
    index: usize,
}

/// An iterator over an OrderedDocument's keys.
pub struct Keys<'a> {
    inner: Map<OrderedDocumentIntoIterator<'a>, fn((&'a String, &'a Bson)) -> &'a String>
}

/// An iterator over an OrderedDocument's values.
pub struct Values<'a> {
    inner: Map<OrderedDocumentIntoIterator<'a>, fn((&'a String, &'a Bson)) -> &'a Bson>
}

impl<'a> Clone for Keys<'a> {
    fn clone(&self) -> Keys<'a> { Keys { inner: self.inner.clone() } }
}

impl<'a> Iterator for Keys<'a> {
    type Item = &'a String;
    fn next(&mut self) -> Option<(&'a String)> { self.inner.next() }
}

impl<'a> Clone for Values<'a> {
    fn clone(&self) -> Values<'a> { Values { inner: self.inner.clone() } }
}

impl<'a> Iterator for Values<'a> {
    type Item = &'a Bson;

    fn next(&mut self) -> Option<(&'a Bson)> { self.inner.next() }
}

impl IntoIterator for OrderedDocument {
    type Item = (String, Bson);
    type IntoIter = OrderedDocumentIterator;

    fn into_iter(self) -> Self::IntoIter {
        OrderedDocumentIterator { ordered_document: self, index: 0 }
    }
}

impl<'a> IntoIterator for &'a OrderedDocument {
    type Item = (&'a String, &'a Bson);
    type IntoIter = OrderedDocumentIntoIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        OrderedDocumentIntoIterator { ordered_document: self, index: 0 }
    }
}

impl FromIterator<(String, Bson)> for OrderedDocument {
    fn from_iter<T: IntoIterator<Item=(String, Bson)>>(iter: T) -> Self {
        let mut doc = OrderedDocument::new();
        for (k, v) in iter {
            doc.insert(k, v.to_owned());
        }
        doc
    }
}

impl<'a> Iterator for OrderedDocumentIterator {
    type Item = (String, Bson);
    fn next(&mut self) -> Option<(String, Bson)> {
        if self.ordered_document.keys.len() <= self.index {
            return None;
        }

        let ref key = self.ordered_document.keys[self.index];
        let val = self.ordered_document.get(&key[..]).unwrap();
        self.index += 1;
        Some((key.to_owned(), val.to_owned()))
    }
}

impl<'a> Iterator for OrderedDocumentIntoIterator<'a> {
    type Item = (&'a String, &'a Bson);
    fn next(&mut self) -> Option<(&'a String, &'a Bson)> {
        if self.ordered_document.keys.len() <= self.index {
            return None;
        }

        let ref key = self.ordered_document.keys[self.index];
        let val = self.ordered_document.get(&key[..]).unwrap();
        self.index += 1;
        Some((key, val))
    }
}

impl OrderedDocument {
    /// Creates a new empty OrderedDocument.
    pub fn new() -> OrderedDocument {
        OrderedDocument {
            keys: Vec::new(),
            document: BTreeMap::new(),
        }
    }

    /// Gets an iterator over the entries of the map.
    pub fn iter<'a>(&'a self) -> OrderedDocumentIntoIterator<'a> {
        self.into_iter()
    }

    /// Clears the document, removing all values.
    pub fn clear(&mut self) {
        self.keys.clear();
        self.document.clear();
    }

    /// Returns a reference to the Bson corresponding to the key.
    pub fn get(&self, key: &str) -> Option<&Bson> {
        self.document.get(key)
    }

    /// Gets a mutable reference to the value in the entry.
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Bson> {
        self.document.get_mut(key)
    }

    /// Returns true if the map contains a value for the specified key.
    pub fn contains_key(&self, key: &str) -> bool {
        self.document.contains_key(key)
    }

    /// Returns the position of the key in the ordered vector, if it exists.
    pub fn position(&self, key: &str) -> Option<usize> {
        self.keys.iter().position(|x| x == key)
    }

    /// Gets a collection of all keys in the document.
    pub fn keys<'a>(&'a self) -> Keys<'a> {
        fn first<A, B>((a, _): (A, B)) -> A { a }
        let first: fn((&'a String, &'a Bson)) -> &'a String = first;

        Keys { inner: self.iter().map(first) }
    }

    /// Gets a collection of all values in the document.
    pub fn values<'a>(&'a self) -> Values<'a> {
        fn second<A, B>((_, b): (A, B)) -> B { b }
        let second: fn((&'a String, &'a Bson)) -> &'a Bson = second;

        Values { inner: self.iter().map(second) }
    }

    /// Returns the number of elements in the document.
    pub fn len(&self) -> usize {
        self.keys.len()
    }

    /// Returns true if the document contains no elements
    pub fn is_empty(&self) -> bool {
        self.document.is_empty()
    }

    /// Sets the value of the entry with the OccupiedEntry's key,
    /// and returns the entry's old value.
    pub fn insert(&mut self, key: String, val: Bson) -> Option<Bson> {
        let key_slice = &key[..];

        if self.contains_key(key_slice) {
            let position = self.position(key_slice).unwrap();
            self.keys.remove(position);
        }

        self.keys.push(key.to_owned());
        self.document.insert(key.to_owned(), val.to_owned())
    }

    /// Takes the value of the entry out of the document, and returns it.
    pub fn remove(&mut self, key: &str) -> Option<Bson> {
        let position = self.position(key);
        if position.is_some() {
            self.keys.remove(position.unwrap());
        }
        self.document.remove(key)
    }
}

#[cfg(test)]
mod test {
    use super::OrderedDocument;
    use bson::Bson;

    #[test]
    fn ordered_insert() {
        let mut doc = OrderedDocument::new();
        doc.insert("first".to_owned(), Bson::I32(1));
        doc.insert("second".to_owned(), Bson::String("foo".to_owned()));
        doc.insert("alphanumeric".to_owned(), Bson::String("bar".to_owned()));

        let expected_keys = vec!(
            "first".to_owned(),
            "second".to_owned(),
            "alphanumeric".to_owned(),
        );

        let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
        assert_eq!(expected_keys, keys);
    }

    #[test]
    fn remove() {
        let mut doc = OrderedDocument::new();
        doc.insert("first".to_owned(), Bson::I32(1));
        doc.insert("second".to_owned(), Bson::String("foo".to_owned()));
        doc.insert("alphanumeric".to_owned(), Bson::String("bar".to_owned()));

        assert!(doc.remove("second").is_some());
        assert!(doc.remove("none").is_none());

        let expected_keys = vec!(
            "first",
            "alphanumeric",
        );

        let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
        assert_eq!(expected_keys, keys);
    }
}
<commit_msg>Swap OrderedDocument iterator names<commit_after>use bson::Bson;
use std::collections::BTreeMap;
use std::iter::{FromIterator, Map};

/// A BSON document represented as an associative BTree Map with insertion ordering.
#[derive(Debug, Clone)]
pub struct OrderedDocument {
    pub keys: Vec<String>,
    document: BTreeMap<String, Bson>,
}

/// An iterator over OrderedDocument entries.
#[derive(Clone)]
pub struct OrderedDocumentIntoIterator {
    ordered_document: OrderedDocument,
    index: usize,
}

/// An owning iterator over OrderedDocument entries.
#[derive(Clone)]
pub struct OrderedDocumentIterator<'a> {
    ordered_document: &'a OrderedDocument,
    index: usize,
}

/// An iterator over an OrderedDocument's keys.
pub struct Keys<'a> {
    inner: Map<OrderedDocumentIterator<'a>, fn((&'a String, &'a Bson)) -> &'a String>
}

/// An iterator over an OrderedDocument's values.
pub struct Values<'a> {
    inner: Map<OrderedDocumentIterator<'a>, fn((&'a String, &'a Bson)) -> &'a Bson>
}

impl<'a> Clone for Keys<'a> {
    fn clone(&self) -> Keys<'a> { Keys { inner: self.inner.clone() } }
}

impl<'a> Iterator for Keys<'a> {
    type Item = &'a String;
    fn next(&mut self) -> Option<(&'a String)> { self.inner.next() }
}

impl<'a> Clone for Values<'a> {
    fn clone(&self) -> Values<'a> { Values { inner: self.inner.clone() } }
}

impl<'a> Iterator for Values<'a> {
    type Item = &'a Bson;

    fn next(&mut self) -> Option<(&'a Bson)> { self.inner.next() }
}

impl IntoIterator for OrderedDocument {
    type Item = (String, Bson);
    type IntoIter = OrderedDocumentIntoIterator;

    fn into_iter(self) -> Self::IntoIter {
        OrderedDocumentIntoIterator { ordered_document: self, index: 0 }
    }
}

impl<'a> IntoIterator for &'a OrderedDocument {
    type Item = (&'a String, &'a Bson);
    type IntoIter = OrderedDocumentIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        OrderedDocumentIterator { ordered_document: self, index: 0 }
    }
}

impl FromIterator<(String, Bson)> for OrderedDocument {
    fn from_iter<T: IntoIterator<Item=(String, Bson)>>(iter: T) -> Self {
        let mut doc = OrderedDocument::new();
        for (k, v) in iter {
            doc.insert(k, v.to_owned());
        }
        doc
    }
}

impl<'a> Iterator for OrderedDocumentIntoIterator {
    type Item = (String, Bson);
    fn next(&mut self) -> Option<(String, Bson)> {
        if self.ordered_document.keys.len() <= self.index {
            return None;
        }

        let ref key = self.ordered_document.keys[self.index];
        let val = self.ordered_document.get(&key[..]).unwrap();
        self.index += 1;
        Some((key.to_owned(), val.to_owned()))
    }
}

impl<'a> Iterator for OrderedDocumentIterator<'a> {
    type Item = (&'a String, &'a Bson);
    fn next(&mut self) -> Option<(&'a String, &'a Bson)> {
        if self.ordered_document.keys.len() <= self.index {
            return None;
        }

        let ref key = self.ordered_document.keys[self.index];
        let val = self.ordered_document.get(&key[..]).unwrap();
        self.index += 1;
        Some((key, val))
    }
}

impl OrderedDocument {
    /// Creates a new empty OrderedDocument.
    pub fn new() -> OrderedDocument {
        OrderedDocument {
            keys: Vec::new(),
            document: BTreeMap::new(),
        }
    }

    /// Gets an iterator over the entries of the map.
    pub fn iter<'a>(&'a self) -> OrderedDocumentIterator<'a> {
        self.into_iter()
    }

    /// Clears the document, removing all values.
    pub fn clear(&mut self) {
        self.keys.clear();
        self.document.clear();
    }

    /// Returns a reference to the Bson corresponding to the key.
    pub fn get(&self, key: &str) -> Option<&Bson> {
        self.document.get(key)
    }

    /// Gets a mutable reference to the value in the entry.
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Bson> {
        self.document.get_mut(key)
    }

    /// Returns true if the map contains a value for the specified key.
    pub fn contains_key(&self, key: &str) -> bool {
        self.document.contains_key(key)
    }

    /// Returns the position of the key in the ordered vector, if it exists.
    pub fn position(&self, key: &str) -> Option<usize> {
        self.keys.iter().position(|x| x == key)
    }

    /// Gets a collection of all keys in the document.
    pub fn keys<'a>(&'a self) -> Keys<'a> {
        fn first<A, B>((a, _): (A, B)) -> A { a }
        let first: fn((&'a String, &'a Bson)) -> &'a String = first;

        Keys { inner: self.iter().map(first) }
    }

    /// Gets a collection of all values in the document.
    pub fn values<'a>(&'a self) -> Values<'a> {
        fn second<A, B>((_, b): (A, B)) -> B { b }
        let second: fn((&'a String, &'a Bson)) -> &'a Bson = second;

        Values { inner: self.iter().map(second) }
    }

    /// Returns the number of elements in the document.
    pub fn len(&self) -> usize {
        self.keys.len()
    }

    /// Returns true if the document contains no elements
    pub fn is_empty(&self) -> bool {
        self.document.is_empty()
    }

    /// Sets the value of the entry with the OccupiedEntry's key,
    /// and returns the entry's old value.
    pub fn insert(&mut self, key: String, val: Bson) -> Option<Bson> {
        let key_slice = &key[..];

        if self.contains_key(key_slice) {
            let position = self.position(key_slice).unwrap();
            self.keys.remove(position);
        }

        self.keys.push(key.to_owned());
        self.document.insert(key.to_owned(), val.to_owned())
    }

    /// Takes the value of the entry out of the document, and returns it.
    pub fn remove(&mut self, key: &str) -> Option<Bson> {
        let position = self.position(key);
        if position.is_some() {
            self.keys.remove(position.unwrap());
        }
        self.document.remove(key)
    }
}

#[cfg(test)]
mod test {
    use super::OrderedDocument;
    use bson::Bson;

    #[test]
    fn ordered_insert() {
        let mut doc = OrderedDocument::new();
        doc.insert("first".to_owned(), Bson::I32(1));
        doc.insert("second".to_owned(), Bson::String("foo".to_owned()));
        doc.insert("alphanumeric".to_owned(), Bson::String("bar".to_owned()));

        let expected_keys = vec!(
            "first".to_owned(),
            "second".to_owned(),
            "alphanumeric".to_owned(),
        );

        let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
        assert_eq!(expected_keys, keys);
    }

    #[test]
    fn remove() {
        let mut doc = OrderedDocument::new();
        doc.insert("first".to_owned(), Bson::I32(1));
        doc.insert("second".to_owned(), Bson::String("foo".to_owned()));
        doc.insert("alphanumeric".to_owned(), Bson::String("bar".to_owned()));

        assert!(doc.remove("second").is_some());
        assert!(doc.remove("none").is_none());

        let expected_keys = vec!(
            "first",
            "alphanumeric",
        );

        let keys: Vec<_> = doc.iter().map(|(key, _)| key.to_owned()).collect();
        assert_eq!(expected_keys, keys);
    }
}
<|endoftext|>


<commit_before>
use std::ops::Fn;
use regex::{Captures, Regex};

/*
 * A Parser is designed to take an input type and turn part of it into an
 * output type.  Probably in every real-life scenario, the input type is a
 * slice of some type.  Thus a parser returns an output type along with another
 * input type, which for slices would be the rest of the data.
 */
pub trait Parser<'a, I, O> {

  fn parse(&self, data: I) -> ParseResult<'a, I, O>;

}

pub type ParseResult<'a, I:'a, O> = Result<(O, I), String>;

pub fn literal<'a, T:'a + Eq + Clone>(literal: T) -> Box<Parser<'a, &'a[T], T> + 'a> {
  box LiteralParser{literal: literal}
}

/*
 * a parser that consumes one item in a slice and only returns ok if it equals
 * the given literal
 */
pub struct LiteralParser<'a, T:'a + Eq + Clone> {
  pub literal: T,
}

impl<'a, T: 'a + Eq + Clone> Parser<'a,  &'a [T], T> for LiteralParser<'a, T> {
  fn parse(&self, data: &'a[T]) -> ParseResult<'a, &'a[T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), data.slice_from(1)))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

/*
 * A string Parser that attempts to consume the given regex
 */
pub struct RegexLiteralParser<'a> {
  pub regex: Regex,
}

impl<'a> Parser<'a, &'a str, ()> for RegexLiteralParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, ()> {
    self.regex.find(data).map(|(_, e)| ((), data.slice_from(e))).ok_or(format!("regex literal match fail"))
  }
}

pub struct RegexCapturesParser<'a> {
  pub regex: Regex,
}
impl<'a> Parser<'a, &'a str, Captures<'a>> for RegexCapturesParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, Captures<'a>> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok((caps, data.slice_from(e))),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

/*
 * A slice Parser that matches against the first item in the slice
 */
pub struct MatchParser<'a, I, O> {
  pub matcher: Box< Fn<(&'a I,), Result<O, String>> +'a>
}
impl<'a, I: Clone, O> Parser<'a, &'a [I], O> for MatchParser<'a, I, O> {
  fn parse(&self, data: &'a[I]) -> ParseResult<'a, &'a[I], O> {
    if data.len() < 1 {
      Err(format!("Unexpected End!"))
    } else {
      self.matcher.call((&data[0],)).map(|res| (res, data.slice_from(1)))
    }
  }
}

/*
 * A Parser that will keep repeating the given parser until it returns an
 * error.  The accumulated results are returned.
 */
pub struct RepParser<'a, I, O>{
  pub parser: Box<Parser<'a, I, O> + 'a>
}

impl<'a, I: Clone, O> Parser<'a, I, Vec<O>> for RepParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

/*
 * A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
 * returns an error.  The accumulated `rep` results are returned.  If `rep`
 * returns an error at any time, the error is escelated.
 */
pub struct RepSepParser<'a, I, O, U> {
  pub rep: Box<Parser<'a, I, O> + 'a>,
  pub sep: Box<Parser<'a, I, U> + 'a>,
  pub min_reps: uint,
}
impl<'a, I: Clone, O, U> Parser<'a, I, Vec<O>> for RepSepParser<'a, I, O, U> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
    unreachable!()
  }
}

/*
 * A Parser that will combine two parsers into a tuple of results.  If either
 * parser returns an error, the error is escelated (ie partial successes are
 * not returned)
 */
pub struct DualParser<'a, I, A, B> {
  pub first: Box<Parser<'a, I, A> + 'a>,
  pub second: Box<Parser<'a, I, B> + 'a>
}

impl <'a, I, A, B> Parser<'a, I, (A,B)> for DualParser<'a, I, A, B> {

  fn parse(&self, data: I) -> ParseResult<'a, I, (A, B)> {
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

/*
 * A parser that will attempt to parse using parser `a`, and then `b` if
 * the first fails.  The sub parsers are lazy so that we can support recursive
 * grammars.
 *
 * In general, the "greedier" parser should be `a`.
 */
pub struct OrParser<'a, I, O> {
  pub a: Box<Fn<(), Box<Parser<'a, I, O> + 'a> + 'a> + 'a>,
  pub b: Box<Fn<(), Box<Parser<'a, I, O> + 'a> + 'a> + 'a>
}

impl<'a, I: Clone, O> Parser<'a, I, O> for OrParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    match self.a.call(()).parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.b.call(()).parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

//this parser doesn't work yet, seems to be some weirdness when trying to put unboxed closures in a vector

pub struct OneOfParser<'a, I, O> {
  parsers: Vec<Box<Fn<(), Box<Parser<'a, I, O> + 'a> + 'a> + 'a> + 'a>
}

impl<'a, I: Clone, O> Parser<'a, I, O> for OneOfParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    for p in self.parsers.iter() {
      let res = p.call(()).parse(data.clone());
      if res.is_ok() {
        return res;
      }
    }
    Err(format!("All options failed"))
  }
}

/*
 * A Parser that can map the successful result of a parser to another type
 */
pub struct MapParser<'a, I, O, U> {
  pub parser: Box<Parser<'a, I, O> + 'a>,
  pub mapper: Box<Fn<(O,), U> +'a>, //this has to be a &Fn and not a regular lambda since it must be immutable
}
impl<'a, I, O, U> Parser<'a, I, U> for MapParser<'a, I, O, U> {
  fn parse(&self, data: I) -> ParseResult<'a, I, U> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper.call((output,)), input)))
  }
}

<commit_msg>new optional parser<commit_after>
use std::ops::Fn;
use regex::{Captures, Regex};

/*
 * A Parser is designed to take an input type and turn part of it into an
 * output type.  Probably in every real-life scenario, the input type is a
 * slice of some type.  Thus a parser returns an output type along with another
 * input type, which for slices would be the rest of the data.
 */
pub trait Parser<'a, I, O> {

  fn parse(&self, data: I) -> ParseResult<'a, I, O>;

}

pub type ParseResult<'a, I:'a, O> = Result<(O, I), String>;

pub fn literal<'a, T:'a + Eq + Clone>(literal: T) -> Box<Parser<'a, &'a[T], T> + 'a> {
  box LiteralParser{literal: literal}
}

/*
 * a parser that consumes one item in a slice and only returns ok if it equals
 * the given literal
 */
pub struct LiteralParser<'a, T:'a + Eq + Clone> {
  pub literal: T,
}

impl<'a, T: 'a + Eq + Clone> Parser<'a,  &'a [T], T> for LiteralParser<'a, T> {
  fn parse(&self, data: &'a[T]) -> ParseResult<'a, &'a[T], T> {
    if data.len() < 1 {
      return Err(format!("ran out of data"))
    }
    if data[0] == self.literal {
      Ok((data[0].clone(), data.slice_from(1)))
    } else {
      Err(format!("Literal mismatch"))
    }
  }
}

/*
 * A string Parser that attempts to consume the given regex
 */
pub struct RegexLiteralParser<'a> {
  pub regex: Regex,
}

impl<'a> Parser<'a, &'a str, ()> for RegexLiteralParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, ()> {
    self.regex.find(data).map(|(_, e)| ((), data.slice_from(e))).ok_or(format!("regex literal match fail"))
  }
}

pub struct RegexCapturesParser<'a> {
  pub regex: Regex,
}
impl<'a> Parser<'a, &'a str, Captures<'a>> for RegexCapturesParser<'a> {
  fn parse(&self, data: &'a str) -> ParseResult<'a, &'a str, Captures<'a>> {
    match self.regex.captures(data) {
      Some(caps) => match caps.pos(0) {
        Some((_, e)) => Ok((caps, data.slice_from(e))),
        None => Err(format!("No Match"))
      },
      None => Err(format!("No Match"))
    }
  }
}

/*
 * A slice Parser that matches against the first item in the slice
 */
pub struct MatchParser<'a, I, O> {
  pub matcher: Box< Fn<(&'a I,), Result<O, String>> +'a>
}
impl<'a, I: Clone, O> Parser<'a, &'a [I], O> for MatchParser<'a, I, O> {
  fn parse(&self, data: &'a[I]) -> ParseResult<'a, &'a[I], O> {
    if data.len() < 1 {
      Err(format!("Unexpected End!"))
    } else {
      self.matcher.call((&data[0],)).map(|res| (res, data.slice_from(1)))
    }
  }
}

/*
 * A Parser that will keep repeating the given parser until it returns an
 * error.  The accumulated results are returned.
 */
pub struct RepParser<'a, I, O>{
  pub parser: Box<Parser<'a, I, O> + 'a>
}

impl<'a, I: Clone, O> Parser<'a, I, Vec<O>> for RepParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.parser.parse(remain.clone()) {
        Ok((result, rest)) => {
          v.push(result);
          remain = rest;
        }
        Err(_) => {
          return Ok((v, remain));
        }
      }
    }
  }
}

/*
 * A Parser that will repeatedly parse `rep` and `sep` in sequence until `sep`
 * returns an error.  The accumulated `rep` results are returned.  If `rep`
 * returns an error at any time, the error is escelated.
 */
pub struct RepSepParser<'a, I, O, U> {
  pub rep: Box<Parser<'a, I, O> + 'a>,
  pub sep: Box<Parser<'a, I, U> + 'a>,
  pub min_reps: uint,
}
impl<'a, I: Clone, O, U> Parser<'a, I, Vec<O>> for RepSepParser<'a, I, O, U> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Vec<O>> {
    let mut remain = data;
    let mut v: Vec<O> = Vec::new();
    loop {
      match self.rep.parse(remain) {
        Ok((result, rest)) => {
          v.push(result);
          match self.sep.parse(rest.clone()) {
            Ok((_, rest2)) => {
              remain = rest2
            }
            Err(_) => {
              if v.len() < self.min_reps {
                return Err(format!("Not enough reps: required {}, got {}", self.min_reps, v.len()))
              } else {
                return Ok((v, rest))
              }
            }
          }
        }
        Err(err) => {
          return Err(format!("Error on rep: {}", err));
        }
      }
    }
    unreachable!()
  }
}

/*
 * A Parser that will combine two parsers into a tuple of results.  If either
 * parser returns an error, the error is escelated (ie partial successes are
 * not returned)
 */
pub struct DualParser<'a, I, A, B> {
  pub first: Box<Parser<'a, I, A> + 'a>,
  pub second: Box<Parser<'a, I, B> + 'a>
}

impl <'a, I, A, B> Parser<'a, I, (A,B)> for DualParser<'a, I, A, B> {

  fn parse(&self, data: I) -> ParseResult<'a, I, (A, B)> {
    match self.first.parse(data) {
      Ok((a, d2)) => match self.second.parse(d2) {
        Ok((b, remain)) => Ok(((a, b), remain)),
        Err(err) => Err(err)
      },
      Err(err) => Err(err)
    }
  }
}

/*
 * A parser that will attempt to parse using parser `a`, and then `b` if
 * the first fails.  The contained parsers are lazy so that we can support recursive
 * grammars.
 *
 * In general, the "greedier" parser should be `a`.
 */
pub struct OrParser<'a, I, O> {
  pub a: Box<Fn<(), Box<Parser<'a, I, O> + 'a> + 'a> + 'a>,
  pub b: Box<Fn<(), Box<Parser<'a, I, O> + 'a> + 'a> + 'a>
}

impl<'a, I: Clone, O> Parser<'a, I, O> for OrParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    match self.a.call(()).parse(data.clone()) {
      Ok((a, d2)) => Ok((a, d2)),
      Err(_) => match self.b.call(()).parse(data.clone()) {
        Ok((b, remain)) => Ok((b, remain)),
        Err(err) => Err(err)
      }
    }
  }
}

//this parser doesn't work yet, seems to be some weirdness when trying to put unboxed closures in a vector

pub struct OneOfParser<'a, I, O> {
  parsers: Vec<Box<Fn<(), Box<Parser<'a, I, O> + 'a> + 'a> + 'a> + 'a>
}

impl<'a, I: Clone, O> Parser<'a, I, O> for OneOfParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, O> {
    for p in self.parsers.iter() {
      let res = p.call(()).parse(data.clone());
      if res.is_ok() {
        return res;
      }
    }
    Err(format!("All options failed"))
  }
}

/*
 * A Parser that can map the successful result of a parser to another type
 */
pub struct MapParser<'a, I, O, U> {
  pub parser: Box<Parser<'a, I, O> + 'a>,
  pub mapper: Box<Fn<(O,), U> +'a>, //this has to be a &Fn and not a regular lambda since it must be immutable
}
impl<'a, I, O, U> Parser<'a, I, U> for MapParser<'a, I, O, U> {
  fn parse(&self, data: I) -> ParseResult<'a, I, U> {
    self.parser.parse(data).map(|(output, input)| ((self.mapper.call((output,)), input)))
  }
}

/*
 * A Parser that will attempt to use a parser, returning an option of the contained parser's result
 */
pub struct OptionParser<'a, I, O> {
  pub parser: Box<Parser<'a, I, O> + 'a>
}
impl<'a, I: Clone, O> Parser<'a, I, Option<O>> for OptionParser<'a, I, O> {
  fn parse(&self, data: I) -> ParseResult<'a, I, Option<O>> {
    match self.parser.parse(data.clone()) {
      Ok((result, rest))  => Ok((Some(result), rest)),
      Err(_)              => Ok((None, data)),
    }
  }
}

<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Traits and essential types inteded for blanket imports.

pub use glib::prelude::*;

pub use auto::traits::*;

pub use app_chooser::AppChooserExt;
pub use assistant::AssistantExtManual;
pub use color_button::ColorButtonExtManual;
pub use color_chooser::ColorChooserExtManual;
pub use css_provider::CssProviderExtManual;
pub use dialog::DialogExtManual;
pub use drag_context::DragContextExtManual;
pub use fixed::FixedExtManual;
pub use list_store::ListStoreExtManual;
pub use menu::MenuExtManual;
pub use notebook::NotebookExtManual;
pub use switch::SwitchExtManual;
pub use text_buffer::TextBufferExtManual;
pub use tree_model_filter::TreeModelFilterExtManual;
pub use tree_sortable::TreeSortableExtManual;
pub use tree_store::TreeStoreExtManual;
pub use widget::WidgetExtManual;

pub use signal::*;
<commit_msg>Fix typo in prelude.rs documentation<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Traits and essential types intended for blanket imports.

pub use glib::prelude::*;

pub use auto::traits::*;

pub use app_chooser::AppChooserExt;
pub use assistant::AssistantExtManual;
pub use color_button::ColorButtonExtManual;
pub use color_chooser::ColorChooserExtManual;
pub use css_provider::CssProviderExtManual;
pub use dialog::DialogExtManual;
pub use drag_context::DragContextExtManual;
pub use fixed::FixedExtManual;
pub use list_store::ListStoreExtManual;
pub use menu::MenuExtManual;
pub use notebook::NotebookExtManual;
pub use switch::SwitchExtManual;
pub use text_buffer::TextBufferExtManual;
pub use tree_model_filter::TreeModelFilterExtManual;
pub use tree_sortable::TreeSortableExtManual;
pub use tree_store::TreeStoreExtManual;
pub use widget::WidgetExtManual;

pub use signal::*;
<|endoftext|>


<commit_before>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
    }
}
<commit_msg>Add program.instruction_pointer<commit_after>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use visitor::FmtVisitor;

use syntax::codemap::{self, BytePos};

impl<'a> FmtVisitor<'a> {
    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end,
                                  |this, last_snippet, _| this.buffer.push_str(last_snippet))
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
                                                                end: BytePos,
                                                                process_last_snippet: F) {
        let start = self.last_pos;
        debug!("format_missing_inner: {:?} to {:?}",
               self.codemap.lookup_char_pos(start),
               self.codemap.lookup_char_pos(end));

        if start == end {
            // Do nothing if this is the beginning of the file.
            if start == self.codemap.lookup_char_pos(start).file.start_pos {
                return;
            }
            process_last_snippet(self, "", "");
            return;
        }

        assert!(start < end,
                "Request to format inverted span: {:?} to {:?}",
                self.codemap.lookup_char_pos(start),
                self.codemap.lookup_char_pos(end));

        self.last_pos = end;
        let span = codemap::mk_sp(start, end);
        let snippet = self.snippet(span);

        self.write_snippet(&snippet, true, &process_last_snippet);
    }

    fn write_snippet<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
                                                         snippet: &str,
                                                         last_snippet: bool,
                                                         process_last_snippet: F) {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let mut line_start = 0;
        let mut last_wspace = None;
        for (i, c) in snippet.char_indices() {
            if c == '\n' {
                if let Some(lw) = last_wspace {
                    self.buffer.push_str(&snippet[line_start..lw]);
                    self.buffer.push_str("\n");
                } else {
                    self.buffer.push_str(&snippet[line_start..i + 1]);
                }

                line_start = i + 1;
                last_wspace = None;
            } else {
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(i);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }
        if last_snippet {
            process_last_snippet(self, &snippet[line_start..], snippet);
        } else {
            self.buffer.push_str(&snippet[line_start..]);
        }
    }
}
<commit_msg>Refactor write_snippet<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use visitor::FmtVisitor;

use syntax::codemap::{self, BytePos};

impl<'a> FmtVisitor<'a> {
    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end,
                                  |this, last_snippet, _| this.buffer.push_str(last_snippet))
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
                                                                end: BytePos,
                                                                process_last_snippet: F) {
        let start = self.last_pos;
        debug!("format_missing_inner: {:?} to {:?}",
               self.codemap.lookup_char_pos(start),
               self.codemap.lookup_char_pos(end));

        if start == end {
            // Do nothing if this is the beginning of the file.
            if start == self.codemap.lookup_char_pos(start).file.start_pos {
                return;
            }
            process_last_snippet(self, "", "");
            return;
        }

        assert!(start < end,
                "Request to format inverted span: {:?} to {:?}",
                self.codemap.lookup_char_pos(start),
                self.codemap.lookup_char_pos(end));

        self.last_pos = end;
        let span = codemap::mk_sp(start, end);
        let snippet = self.snippet(span);

        self.write_snippet(&snippet, &process_last_snippet);
    }

    fn write_snippet<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
                                                         snippet: &str,
                                                         process_last_snippet: F) {
        let mut lines: Vec<&str> = snippet.lines().collect();
        let last_snippet = if snippet.ends_with("\n") {
            ""
        } else {
            lines.pop().unwrap()
        };
        for line in lines.iter() {
            self.buffer.push_str(line.trim_right());
            self.buffer.push_str("\n");
        }
        process_last_snippet(self, &last_snippet, snippet);
    }
}
<|endoftext|>


<commit_before>#![deny(rust_2018_idioms)]

use cargo::{
    core::{
        compiler::{CompileKind, CompileTarget, TargetInfo},
        package::PackageSet,
        registry::PackageRegistry,
        resolver::{self, features::RequestedFeatures, ResolveOpts, VersionPreferences},
        source::SourceMap,
        Dependency, Package, PackageId, Source, SourceId, Summary, TargetKind,
    },
    sources::RegistrySource,
    util::{interning::InternedString, Config, VersionExt},
};
use itertools::Itertools;
use semver::Version;
use serde::{Deserialize, Serialize};
use std::{
    collections::{BTreeMap, BTreeSet, HashSet},
    io::Read,
    task::Poll,
};

const PLAYGROUND_TARGET_PLATFORM: &str = "x86_64-unknown-linux-gnu";

struct GlobalState<'cfg> {
    config: &'cfg Config,
    target_info: TargetInfo,
    registry: PackageRegistry<'cfg>,
    crates_io: SourceId,
    source: RegistrySource<'cfg>,
    modifications: &'cfg Modifications,
}

/// The list of crates from crates.io
#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

/// The shared description of a crate
#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename = "id")]
    name: InternedString,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
pub struct CrateInformation {
    pub name: String,
    pub version: Version,
    pub id: String,
}

/// Hand-curated changes to the crate list
#[derive(Debug, Default, Deserialize)]
pub struct Modifications {
    #[serde(default)]
    pub exclusions: Vec<InternedString>,
    #[serde(default)]
    pub additions: BTreeSet<InternedString>,
}

#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct DependencySpec {
    #[serde(skip_serializing_if = "String::is_empty")]
    pub package: String,
    #[serde(serialize_with = "exact_version")]
    pub version: Version,
    #[serde(skip_serializing_if = "BTreeSet::is_empty")]
    pub features: BTreeSet<InternedString>,
    #[serde(skip_serializing_if = "is_true")]
    pub default_features: bool,
}

fn exact_version<S>(version: &Version, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    semver::Comparator {
        op: semver::Op::Exact,
        major: version.major,
        minor: Some(version.minor),
        patch: Some(version.patch),
        pre: version.pre.clone(),
    }
    .serialize(serializer)
}

fn is_true(b: &bool) -> bool {
    *b
}

impl Modifications {
    fn excluded(&self, name: &str) -> bool {
        self.exclusions.iter().any(|n| n == name)
    }
}

fn simple_get(url: &str) -> reqwest::Result<reqwest::blocking::Response> {
    reqwest::blocking::ClientBuilder::new()
        .user_agent("Rust Playground - Top Crates Utility")
        .build()?
        .get(url)
        .send()
}

impl TopCrates {
    /// List top 100 crates by number of downloads on crates.io.
    fn download() -> TopCrates {
        let resp = simple_get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
            .expect("Could not fetch top crates");
        assert!(
            resp.status().is_success(),
            "Could not download top crates; HTTP status was {}",
            resp.status(),
        );

        serde_json::from_reader(resp).expect("Invalid JSON")
    }

    fn add_rust_cookbook_crates(&mut self) {
        let mut resp = simple_get(
            "https://raw.githubusercontent.com/rust-lang-nursery/rust-cookbook/master/Cargo.toml",
        )
        .expect("Could not fetch cookbook manifest");
        assert!(
            resp.status().is_success(),
            "Could not download cookbook; HTTP status was {}",
            resp.status(),
        );

        let mut content = String::new();
        resp.read_to_string(&mut content)
            .expect("could not read cookbook manifest");

        let manifest = content
            .parse::<toml::Value>()
            .expect("could not parse cookbook manifest");

        let dependencies = manifest["dependencies"]
            .as_table()
            .expect("no dependencies found for cookbook manifest");
        self.crates.extend({
            dependencies.iter().map(|(name, _)| Crate {
                name: InternedString::new(name),
            })
        })
    }

    /// Add crates that have been hand-picked
    fn add_curated_crates(&mut self, modifications: &Modifications) {
        self.crates.extend({
            modifications
                .additions
                .iter()
                .copied()
                .map(|name| Crate { name })
        });
    }
}

/// Finds the features specified by the custom metadata of `pkg`.
///
/// Our custom metadata format looks like:
///
///     [package.metadata.playground]
///     default-features = true
///     features = ["std", "extra-traits"]
///     all-features = false
///
/// All fields are optional.
fn playground_metadata_features(pkg: &Package) -> Option<(BTreeSet<InternedString>, bool)> {
    let custom_metadata = pkg.manifest().custom_metadata()?;
    let playground_metadata = custom_metadata.get("playground")?;

    #[derive(Deserialize)]
    #[serde(default, rename_all = "kebab-case")]
    struct Metadata {
        features: BTreeSet<InternedString>,
        default_features: bool,
        all_features: bool,
    }

    impl Default for Metadata {
        fn default() -> Self {
            Metadata {
                features: BTreeSet::new(),
                default_features: true,
                all_features: false,
            }
        }
    }

    let metadata = match playground_metadata.clone().try_into::<Metadata>() {
        Ok(metadata) => metadata,
        Err(err) => {
            eprintln!(
                "Failed to parse custom metadata for {} {}: {}",
                pkg.name(),
                pkg.version(),
                err
            );
            return None;
        }
    };

    // If `all-features` is set then we ignore `features`.
    let summary = pkg.summary();
    let mut enabled_features: BTreeSet<InternedString> = if metadata.all_features {
        summary.features().keys().copied().collect()
    } else {
        metadata.features
    };

    // If not opting out of default features, remove default features from the
    // explicit features list. This avoids ongoing spurious diffs in our
    // generated Cargo.toml as default features are added to a library.
    if metadata.default_features {
        if let Some(default_feature_names) = summary.features().get("default") {
            enabled_features.remove("default");
            for feature in default_feature_names {
                enabled_features.remove(&InternedString::new(&feature.to_string()));
            }
        }
    }

    if !enabled_features.is_empty() || !metadata.default_features {
        Some((enabled_features, metadata.default_features))
    } else {
        None
    }
}

fn make_global_state<'cfg>(
    config: &'cfg Config,
    modifications: &'cfg Modifications,
) -> GlobalState<'cfg> {
    // Information about the playground's target platform.
    let compile_target =
        CompileTarget::new(PLAYGROUND_TARGET_PLATFORM).expect("Unable to create a CompileTarget");
    let compile_kind = CompileKind::Target(compile_target);
    let rustc = config
        .load_global_rustc(None)
        .expect("Unable to load the global rustc");
    let target_info = TargetInfo::new(config, &[compile_kind], &rustc, compile_kind)
        .expect("Unable to create a TargetInfo");

    // Registry of known packages.
    let mut registry = PackageRegistry::new(config).expect("Unable to create package registry");
    registry.lock_patches();

    // Source for obtaining packages from the crates.io registry.
    let crates_io = SourceId::crates_io(config).expect("Unable to create crates.io source ID");
    let yanked_whitelist = HashSet::new();
    let mut source = RegistrySource::remote(crates_io, &yanked_whitelist, config)
        .expect("Unable to create registry source");
    source.invalidate_cache();
    source
        .block_until_ready()
        .expect("Unable to wait for registry to be ready");

    GlobalState {
        config,
        target_info,
        registry,
        crates_io,
        source,
        modifications,
    }
}

fn bulk_download(global: &mut GlobalState<'_>, package_ids: &[PackageId]) -> Vec<Package> {
    let mut sources = SourceMap::new();
    sources.insert(Box::new(&mut global.source));

    let package_set = PackageSet::new(package_ids, sources, global.config)
        .expect("Unable to create a PackageSet");

    package_set
        .get_many(package_set.package_ids())
        .expect("Unable to download packages")
        .into_iter()
        .map(Package::clone)
        .collect()
}

fn populate_initial_direct_dependencies(
    global: &mut GlobalState<'_>,
) -> Vec<(Summary, ResolveOpts)> {
    let mut top = TopCrates::download();
    top.add_rust_cookbook_crates();
    top.add_curated_crates(global.modifications);

    // Find the newest (non-prerelease, non-yanked) versions of all
    // the interesting crates.
    let mut summaries = Vec::new();
    for Crate { name } in top.crates {
        if global.modifications.excluded(&name) {
            continue;
        }

        // Query the registry for a summary of this crate.
        // Usefully, this doesn't seem to include yanked versions
        let version = None;
        let dep = Dependency::parse(name, version, global.crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}: {}", name, e));

        let matches = match global.source.query_vec(&dep) {
            Poll::Ready(Ok(v)) => v,
            Poll::Ready(Err(e)) => panic!("Unable to query registry for {}: {}", name, e),
            Poll::Pending => panic!("Registry not ready to query"),
        };

        // Find the newest non-prelease version
        let summary = matches
            .into_iter()
            .filter(|summary| !summary.version().is_prerelease())
            .max_by_key(|summary| summary.version().clone())
            .unwrap_or_else(|| panic!("Registry has no viable versions of {}", name));

        // Add a dependency on this crate.
        summaries.push((
            summary,
            ResolveOpts {
                dev_deps: false,
                features: RequestedFeatures::DepFeatures {
                    features: Default::default(),
                    uses_default_features: true,
                },
            },
        ));
    }

    summaries
}

fn compute_transitive_dependencies(
    global: &mut GlobalState<'_>,
    summaries: Vec<(Summary, ResolveOpts)>,
) -> Vec<PackageId> {
    // Resolve transitive dependencies.
    let replacements = [];
    let version_prefs = VersionPreferences::default();
    let warnings = None;
    let check_public_visible_dependencies = true;
    let resolve = resolver::resolve(
        &summaries,
        &replacements,
        &mut global.registry,
        &version_prefs,
        warnings,
        check_public_visible_dependencies,
    )
    .expect("Unable to resolve dependencies");

    // Find crates incompatible with the playground's platform
    let mut valid_for_our_platform: BTreeSet<_> =
        summaries.iter().map(|(s, _)| s.package_id()).collect();

    let mut to_visit = valid_for_our_platform.clone();

    while !to_visit.is_empty() {
        let mut visit_next = BTreeSet::new();

        for package_id in to_visit {
            for (dep_pkg, deps) in resolve.deps(package_id) {
                let for_this_platform = deps.iter().any(|dep| {
                    dep.platform().map_or(true, |platform| {
                        platform.matches(PLAYGROUND_TARGET_PLATFORM, global.target_info.cfg())
                    })
                });

                if for_this_platform {
                    valid_for_our_platform.insert(dep_pkg);
                    visit_next.insert(dep_pkg);
                }
            }
        }

        to_visit = visit_next;
    }

    // Remove invalid and excluded packages that have been added due to resolution
    resolve
        .iter()
        .filter(|pkg| valid_for_our_platform.contains(pkg))
        .filter(|pkg| !global.modifications.excluded(pkg.name().as_str()))
        .collect()
}

pub fn generate_info(
    modifications: &Modifications,
) -> (BTreeMap<String, DependencySpec>, Vec<CrateInformation>) {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let _lock = config.acquire_package_cache_lock();
    let mut global = make_global_state(&config, modifications);

    let summaries = populate_initial_direct_dependencies(&mut global);
    let package_ids = compute_transitive_dependencies(&mut global, summaries);
    let packages = bulk_download(&mut global, &package_ids);
    let dependencies = generate_dependency_specs(packages);
    let infos = generate_crate_information(&dependencies);
    (dependencies, infos)
}

fn generate_dependency_specs(mut packages: Vec<Package>) -> BTreeMap<String, DependencySpec> {
    // Sort all packages by name then version (descending), so that
    // when we group them we know we get all the same crates together
    // and the newest version first.
    packages.sort_by(|a, b| {
        a.name()
            .cmp(&b.name())
            .then(a.version().cmp(&b.version()).reverse())
    });

    let mut dependencies = BTreeMap::new();
    for (name, pkgs) in &packages.into_iter().group_by(|pkg| pkg.name()) {
        let mut first = true;

        for pkg in pkgs {
            let version = pkg.version();

            let crate_name = pkg
                .targets()
                .iter()
                .flat_map(|target| match target.kind() {
                    TargetKind::Lib(_) => Some(target.crate_name()),
                    _ => None,
                })
                .next()
                .unwrap_or_else(|| panic!("{} did not have a library", name));

            // We see the newest version first. Any subsequent
            // versions will have their version appended so that they
            // are uniquely named
            let exposed_name = if first {
                crate_name.clone()
            } else {
                format!(
                    "{}_{}_{}_{}",
                    crate_name, version.major, version.minor, version.patch
                )
            };

            let (features, default_features) =
                playground_metadata_features(&pkg).unwrap_or_else(|| (BTreeSet::new(), true));

            dependencies.insert(
                exposed_name.clone(),
                DependencySpec {
                    package: name.to_string(),
                    version: version.clone(),
                    features,
                    default_features,
                },
            );

            first = false;
        }
    }

    dependencies
}

fn generate_crate_information(
    dependencies: &BTreeMap<String, DependencySpec>,
) -> Vec<CrateInformation> {
    let mut infos = Vec::new();

    for (exposed_name, dependency_spec) in dependencies {
        infos.push(CrateInformation {
            name: dependency_spec.package.clone(),
            version: dependency_spec.version.clone(),
            id: exposed_name.clone(),
        });
    }

    infos
}
<commit_msg>Use nicer way to get crate name of the library target<commit_after>#![deny(rust_2018_idioms)]

use cargo::{
    core::{
        compiler::{CompileKind, CompileTarget, TargetInfo},
        package::PackageSet,
        registry::PackageRegistry,
        resolver::{self, features::RequestedFeatures, ResolveOpts, VersionPreferences},
        source::SourceMap,
        Dependency, Package, PackageId, Source, SourceId, Summary,
    },
    sources::RegistrySource,
    util::{interning::InternedString, Config, VersionExt},
};
use itertools::Itertools;
use semver::Version;
use serde::{Deserialize, Serialize};
use std::{
    collections::{BTreeMap, BTreeSet, HashSet},
    io::Read,
    task::Poll,
};

const PLAYGROUND_TARGET_PLATFORM: &str = "x86_64-unknown-linux-gnu";

struct GlobalState<'cfg> {
    config: &'cfg Config,
    target_info: TargetInfo,
    registry: PackageRegistry<'cfg>,
    crates_io: SourceId,
    source: RegistrySource<'cfg>,
    modifications: &'cfg Modifications,
}

/// The list of crates from crates.io
#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

/// The shared description of a crate
#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename = "id")]
    name: InternedString,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
pub struct CrateInformation {
    pub name: String,
    pub version: Version,
    pub id: String,
}

/// Hand-curated changes to the crate list
#[derive(Debug, Default, Deserialize)]
pub struct Modifications {
    #[serde(default)]
    pub exclusions: Vec<InternedString>,
    #[serde(default)]
    pub additions: BTreeSet<InternedString>,
}

#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct DependencySpec {
    #[serde(skip_serializing_if = "String::is_empty")]
    pub package: String,
    #[serde(serialize_with = "exact_version")]
    pub version: Version,
    #[serde(skip_serializing_if = "BTreeSet::is_empty")]
    pub features: BTreeSet<InternedString>,
    #[serde(skip_serializing_if = "is_true")]
    pub default_features: bool,
}

fn exact_version<S>(version: &Version, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    semver::Comparator {
        op: semver::Op::Exact,
        major: version.major,
        minor: Some(version.minor),
        patch: Some(version.patch),
        pre: version.pre.clone(),
    }
    .serialize(serializer)
}

fn is_true(b: &bool) -> bool {
    *b
}

impl Modifications {
    fn excluded(&self, name: &str) -> bool {
        self.exclusions.iter().any(|n| n == name)
    }
}

fn simple_get(url: &str) -> reqwest::Result<reqwest::blocking::Response> {
    reqwest::blocking::ClientBuilder::new()
        .user_agent("Rust Playground - Top Crates Utility")
        .build()?
        .get(url)
        .send()
}

impl TopCrates {
    /// List top 100 crates by number of downloads on crates.io.
    fn download() -> TopCrates {
        let resp = simple_get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
            .expect("Could not fetch top crates");
        assert!(
            resp.status().is_success(),
            "Could not download top crates; HTTP status was {}",
            resp.status(),
        );

        serde_json::from_reader(resp).expect("Invalid JSON")
    }

    fn add_rust_cookbook_crates(&mut self) {
        let mut resp = simple_get(
            "https://raw.githubusercontent.com/rust-lang-nursery/rust-cookbook/master/Cargo.toml",
        )
        .expect("Could not fetch cookbook manifest");
        assert!(
            resp.status().is_success(),
            "Could not download cookbook; HTTP status was {}",
            resp.status(),
        );

        let mut content = String::new();
        resp.read_to_string(&mut content)
            .expect("could not read cookbook manifest");

        let manifest = content
            .parse::<toml::Value>()
            .expect("could not parse cookbook manifest");

        let dependencies = manifest["dependencies"]
            .as_table()
            .expect("no dependencies found for cookbook manifest");
        self.crates.extend({
            dependencies.iter().map(|(name, _)| Crate {
                name: InternedString::new(name),
            })
        })
    }

    /// Add crates that have been hand-picked
    fn add_curated_crates(&mut self, modifications: &Modifications) {
        self.crates.extend({
            modifications
                .additions
                .iter()
                .copied()
                .map(|name| Crate { name })
        });
    }
}

/// Finds the features specified by the custom metadata of `pkg`.
///
/// Our custom metadata format looks like:
///
///     [package.metadata.playground]
///     default-features = true
///     features = ["std", "extra-traits"]
///     all-features = false
///
/// All fields are optional.
fn playground_metadata_features(pkg: &Package) -> Option<(BTreeSet<InternedString>, bool)> {
    let custom_metadata = pkg.manifest().custom_metadata()?;
    let playground_metadata = custom_metadata.get("playground")?;

    #[derive(Deserialize)]
    #[serde(default, rename_all = "kebab-case")]
    struct Metadata {
        features: BTreeSet<InternedString>,
        default_features: bool,
        all_features: bool,
    }

    impl Default for Metadata {
        fn default() -> Self {
            Metadata {
                features: BTreeSet::new(),
                default_features: true,
                all_features: false,
            }
        }
    }

    let metadata = match playground_metadata.clone().try_into::<Metadata>() {
        Ok(metadata) => metadata,
        Err(err) => {
            eprintln!(
                "Failed to parse custom metadata for {} {}: {}",
                pkg.name(),
                pkg.version(),
                err
            );
            return None;
        }
    };

    // If `all-features` is set then we ignore `features`.
    let summary = pkg.summary();
    let mut enabled_features: BTreeSet<InternedString> = if metadata.all_features {
        summary.features().keys().copied().collect()
    } else {
        metadata.features
    };

    // If not opting out of default features, remove default features from the
    // explicit features list. This avoids ongoing spurious diffs in our
    // generated Cargo.toml as default features are added to a library.
    if metadata.default_features {
        if let Some(default_feature_names) = summary.features().get("default") {
            enabled_features.remove("default");
            for feature in default_feature_names {
                enabled_features.remove(&InternedString::new(&feature.to_string()));
            }
        }
    }

    if !enabled_features.is_empty() || !metadata.default_features {
        Some((enabled_features, metadata.default_features))
    } else {
        None
    }
}

fn make_global_state<'cfg>(
    config: &'cfg Config,
    modifications: &'cfg Modifications,
) -> GlobalState<'cfg> {
    // Information about the playground's target platform.
    let compile_target =
        CompileTarget::new(PLAYGROUND_TARGET_PLATFORM).expect("Unable to create a CompileTarget");
    let compile_kind = CompileKind::Target(compile_target);
    let rustc = config
        .load_global_rustc(None)
        .expect("Unable to load the global rustc");
    let target_info = TargetInfo::new(config, &[compile_kind], &rustc, compile_kind)
        .expect("Unable to create a TargetInfo");

    // Registry of known packages.
    let mut registry = PackageRegistry::new(config).expect("Unable to create package registry");
    registry.lock_patches();

    // Source for obtaining packages from the crates.io registry.
    let crates_io = SourceId::crates_io(config).expect("Unable to create crates.io source ID");
    let yanked_whitelist = HashSet::new();
    let mut source = RegistrySource::remote(crates_io, &yanked_whitelist, config)
        .expect("Unable to create registry source");
    source.invalidate_cache();
    source
        .block_until_ready()
        .expect("Unable to wait for registry to be ready");

    GlobalState {
        config,
        target_info,
        registry,
        crates_io,
        source,
        modifications,
    }
}

fn bulk_download(global: &mut GlobalState<'_>, package_ids: &[PackageId]) -> Vec<Package> {
    let mut sources = SourceMap::new();
    sources.insert(Box::new(&mut global.source));

    let package_set = PackageSet::new(package_ids, sources, global.config)
        .expect("Unable to create a PackageSet");

    package_set
        .get_many(package_set.package_ids())
        .expect("Unable to download packages")
        .into_iter()
        .map(Package::clone)
        .collect()
}

fn populate_initial_direct_dependencies(
    global: &mut GlobalState<'_>,
) -> Vec<(Summary, ResolveOpts)> {
    let mut top = TopCrates::download();
    top.add_rust_cookbook_crates();
    top.add_curated_crates(global.modifications);

    // Find the newest (non-prerelease, non-yanked) versions of all
    // the interesting crates.
    let mut summaries = Vec::new();
    for Crate { name } in top.crates {
        if global.modifications.excluded(&name) {
            continue;
        }

        // Query the registry for a summary of this crate.
        // Usefully, this doesn't seem to include yanked versions
        let version = None;
        let dep = Dependency::parse(name, version, global.crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}: {}", name, e));

        let matches = match global.source.query_vec(&dep) {
            Poll::Ready(Ok(v)) => v,
            Poll::Ready(Err(e)) => panic!("Unable to query registry for {}: {}", name, e),
            Poll::Pending => panic!("Registry not ready to query"),
        };

        // Find the newest non-prelease version
        let summary = matches
            .into_iter()
            .filter(|summary| !summary.version().is_prerelease())
            .max_by_key(|summary| summary.version().clone())
            .unwrap_or_else(|| panic!("Registry has no viable versions of {}", name));

        // Add a dependency on this crate.
        summaries.push((
            summary,
            ResolveOpts {
                dev_deps: false,
                features: RequestedFeatures::DepFeatures {
                    features: Default::default(),
                    uses_default_features: true,
                },
            },
        ));
    }

    summaries
}

fn compute_transitive_dependencies(
    global: &mut GlobalState<'_>,
    summaries: Vec<(Summary, ResolveOpts)>,
) -> Vec<PackageId> {
    // Resolve transitive dependencies.
    let replacements = [];
    let version_prefs = VersionPreferences::default();
    let warnings = None;
    let check_public_visible_dependencies = true;
    let resolve = resolver::resolve(
        &summaries,
        &replacements,
        &mut global.registry,
        &version_prefs,
        warnings,
        check_public_visible_dependencies,
    )
    .expect("Unable to resolve dependencies");

    // Find crates incompatible with the playground's platform
    let mut valid_for_our_platform: BTreeSet<_> =
        summaries.iter().map(|(s, _)| s.package_id()).collect();

    let mut to_visit = valid_for_our_platform.clone();

    while !to_visit.is_empty() {
        let mut visit_next = BTreeSet::new();

        for package_id in to_visit {
            for (dep_pkg, deps) in resolve.deps(package_id) {
                let for_this_platform = deps.iter().any(|dep| {
                    dep.platform().map_or(true, |platform| {
                        platform.matches(PLAYGROUND_TARGET_PLATFORM, global.target_info.cfg())
                    })
                });

                if for_this_platform {
                    valid_for_our_platform.insert(dep_pkg);
                    visit_next.insert(dep_pkg);
                }
            }
        }

        to_visit = visit_next;
    }

    // Remove invalid and excluded packages that have been added due to resolution
    resolve
        .iter()
        .filter(|pkg| valid_for_our_platform.contains(pkg))
        .filter(|pkg| !global.modifications.excluded(pkg.name().as_str()))
        .collect()
}

pub fn generate_info(
    modifications: &Modifications,
) -> (BTreeMap<String, DependencySpec>, Vec<CrateInformation>) {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let _lock = config.acquire_package_cache_lock();
    let mut global = make_global_state(&config, modifications);

    let summaries = populate_initial_direct_dependencies(&mut global);
    let package_ids = compute_transitive_dependencies(&mut global, summaries);
    let packages = bulk_download(&mut global, &package_ids);
    let dependencies = generate_dependency_specs(packages);
    let infos = generate_crate_information(&dependencies);
    (dependencies, infos)
}

fn generate_dependency_specs(mut packages: Vec<Package>) -> BTreeMap<String, DependencySpec> {
    // Sort all packages by name then version (descending), so that
    // when we group them we know we get all the same crates together
    // and the newest version first.
    packages.sort_by(|a, b| {
        a.name()
            .cmp(&b.name())
            .then(a.version().cmp(&b.version()).reverse())
    });

    let mut dependencies = BTreeMap::new();
    for (name, pkgs) in &packages.into_iter().group_by(|pkg| pkg.name()) {
        let mut first = true;

        for pkg in pkgs {
            let version = pkg.version();

            let crate_name = pkg
                .library()
                .unwrap_or_else(|| panic!("{} did not have a library", name))
                .crate_name();

            // We see the newest version first. Any subsequent
            // versions will have their version appended so that they
            // are uniquely named
            let exposed_name = if first {
                crate_name.clone()
            } else {
                format!(
                    "{}_{}_{}_{}",
                    crate_name, version.major, version.minor, version.patch
                )
            };

            let (features, default_features) =
                playground_metadata_features(&pkg).unwrap_or_else(|| (BTreeSet::new(), true));

            dependencies.insert(
                exposed_name.clone(),
                DependencySpec {
                    package: name.to_string(),
                    version: version.clone(),
                    features,
                    default_features,
                },
            );

            first = false;
        }
    }

    dependencies
}

fn generate_crate_information(
    dependencies: &BTreeMap<String, DependencySpec>,
) -> Vec<CrateInformation> {
    let mut infos = Vec::new();

    for (exposed_name, dependency_spec) in dependencies {
        infos.push(CrateInformation {
            name: dependency_spec.package.clone(),
            version: dependency_spec.version.clone(),
            id: exposed_name.clone(),
        });
    }

    infos
}
<|endoftext|>


<commit_before>use std::iter;

use device::Device;

/// Trait implemented on structs that describe a buffer layout.
///
/// The API will accept any buffer whose content implements `Layout` where the `RawLayout` matches
/// what is expected. This way you can create multiple structs compatible with each other.
pub unsafe trait Layout {
    type RawLayout;
}

/// Represents the layout of the resources and data that can be binded before drawing and that will
/// be accessible from the shaders.
///
/// The template parameter represents the descriptor sets.
// TODO: push constants.
pub struct PipelineLayout<DescriptorSets> {
    device: Arc<Device>,
    layout: VkPipelineLayout,
}

impl<DescriptorSets> PipelineLayout<DescriptorSets> {
    /// Creates a new `PipelineLayout`.
    pub fn new(device: &Arc<Device>) -> Result<Arc<PipelineLayout<L>>, > {
        let layout = unsafe {
            let infos = VkPipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: ,
                pSetLayouts: ,
                pushConstantRangeCount: ,
                pPushConstantRanges: ,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreatePipelineLayout(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(PipelineLayout {
            device: device.clone(),
            layout: layout,
        }))
    }
}

pub trait DescriptorDef {
    type BindData;
}

pub struct StorageImageMarker;

pub struct SamplerMarker;

pub struct SampledImageMarker;

pub struct CombinedImageSamplerMarker;

pub struct UniformTexelBufferMarker<T: ?Sized, M>(Buffer<T, M>);

pub struct StorageTexelBufferMarker<T: ?Sized, M>(Buffer<T, M>);

pub struct UniformBufferMarker<T: ?Sized, M>(Buffer<T, M>);

pub struct StorageBufferMarker<T: ?Sized, M>(Buffer<T, M>);

pub struct DynamicUniformBufferMarker<T: ?Sized, M>(Buffer<T, M>);

pub struct DynamicStorageBufferMarker<T: ?Sized, M>(Buffer<T, M>);

pub struct InputAttachmentMarker;

pub trait DescriptorSetDefinition {
    type Raw;

    fn into_raw(self) -> Self::Raw;
}

pub struct DescriptorSetLayout<D> {
    device: Arc<Device>,
    layout: vk::DescriptorSetLayout,
    marker: PhantomData<D>,
}

impl<D> DescriptorSetLayout<D> where D: DescriptorSetDefinition {
    pub fn new(device: &Arc<Device>) -> Result<Arc<DescriptorSetLayout<D>> {
        let vk = device.pointers();

        let bindings = ;

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(DescriptorSetLayout {
            device: device.clone(),
            layout: layout,
            marker: PhantomData,
        }))
    }
}

impl DescriptorSet {
    pub fn new<I>(device: &Arc<Device>, descriptors: I) -> Arc<DescriptorSet>
        where I: IntoIterator<Item = Descriptor>
    {
        let descriptors: Vec<_> = descriptors.into_iter().map(|descriptor| {
            let stage_flags =
                if descriptor.stages.vertex { vk::SHADER_STAGE_VERTEX_BIT } else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT }
                else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT }
                else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_GEOMETRY_BIT } else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_FRAGMENT_BIT } else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_COMPUTE_BIT } else { 0 };

            // TODO: check array size limits

            VkDescriptorSetLayoutBinding {
                descriptorType: ,
                arraySize: descriptor.array_size,
                stageFlags: stage_flags,
                pImmutableSamplers: ,
            }
        }).collect();

        vkCreateDescriptorSetLayout
    }

    #[inline]
    pub fn write(&self) {
        DescriptorSet::update(Some(write), iter::empty())
    }

    #[inline]
    pub fn copy(&self) {
        DescriptorSet::update(iter::empty(), Some(copy))
    }

    #[inline]
    pub fn multi_write<I>(writes: I) {
        DescriptorSet::update(writes, iter::empty())
    }

    #[inline]
    pub fn multi_copy<I>(copies: I) {
        DescriptorSet::update(iter::empty(), copies)
    }

    pub fn update(writes: I, copies: J) {

    }
}

pub struct Descriptor {
    pub ty: DescriptorType,
    pub array_size: u32,
    pub stages: ShaderStages,
}

pub enum DescriptorType {
    Sampler,
    CombinedImageSampler,
    SampledImage,
    StorageImage,
    UniformTexelBuffer,
    StorageTexelBuffer,
    UniformBuffer,
    StorageBuffer,
    UniformBufferDynamic,
    StorageBufferDynamic,
    InputAttachment,
}

pub struct ShaderStages {
    pub vertex: bool,
    pub tessellation_control: bool,
    pub tessellation_evaluation: bool,
    pub geometry: bool,
    pub fragment: bool,
    pub compute: bool,
}
<commit_msg>Draft for descriptor sets<commit_after>

How does that work?

The shader analyser determines which descriptors are used by each shader and outputs a struct
that describes this stuff. This struct implements `PipelineLayoutDesc`.

When shaders are grouped together in the pipeline, they are passed through `CompatiblePipeline`
to be merged into a single pipeline layout struct. If the descriptors of the various shaders
are incompatible, it is detected at that moment.

The single struct that represents the layout is stored as a template parameter of the pipeline.
It is also stored in the `PipelineLayout` object (which wraps around vulkan's pipeline layout).
When you draw, you have to pass a collection of descriptor sets that are compatible with the
pipeline layout desc of the pipeline.

use std::iter;

use device::Device;

/// Trait implemented on structs that describe a buffer layout.
///
/// The API will accept any buffer whose content implements `Layout` where the `RawLayout` matches
/// what is expected. This way you can create multiple structs compatible with each other.
pub unsafe trait Layout {
    type RawLayout;
}

pub unsafe trait PipelineLayoutDesc {
    type DescriptorSets;
    type PushConstants;
}

// example: impl PipelineLayoutDesc for (CustomFrag1, CustomFrag2, CustomFrag3) {}

pub unsafe trait CompatiblePipeline<T> { type Out; }
pub unsafe trait CompatibleSet<T> { type Out; }

macro_rules! impl_tuple {
    (($in_first:ident $out_first:ident) $(, ($in_rest:ident $out_rest:ident))*) => {
        unsafe impl<$in_first, $out_first $(, $in_rest, $out_rest)*>
            CompatibleSet<($out_first, $($out_rest,)*)> for ($in_first, $($in_rest,)*)
                where $in_first: CompatibleDescriptor<$out_first> $(, $in_rest: CompatibleDescriptor<$out_rest>)*
        {
            type Out = (
                <$in_first as CompatibleDescriptor<$out_first>>::Out,
                $(
                    <$in_rest as CompatibleDescriptor<$out_rest>>::Out,
                )*
            );
        }

        unsafe impl<$in_first, $out_first $(, $in_rest, $out_rest)*>
            CompatiblePipeline<($out_first, $($out_rest,)*)> for ($in_first, $($in_rest,)*)
                where $in_first: CompatibleSet<$out_first> $(, $in_rest: CompatibleSet<$out_rest>)*
        {
            type Out = (
                <$in_first as CompatibleSet<$out_first>>::Out,
                $(
                    <$in_rest as CompatibleSet<$out_rest>>::Out,
                )*
            );
        }

        impl_tuple!{$(($in_rest $out_rest)),*}
    };

    () => ();
}

impl_tuple!( (A N), (B O), (C P), (D Q), (E R), (F S), (G T),
             (H U), (I V), (J W), (K X), (L Y), (M Z) );

/// If a type `A` can be interpreted as a `T`, then `A` will implement `CompatibleDescriptor<T>`.
trait CompatibleDescriptor<T> { type Out; }

impl CompatibleDescriptor<()> for () { type Out = (); }
impl<T> CompatibleDescriptor<()> for T where T: Descriptor { type Out = T; }
impl<T> CompatibleDescriptor<T> for () where T: Descriptor { type Out = T; }
impl<T> CompatibleDescriptor<T> for T where T: Descriptor { type Out = T; }

pub unsafe trait Descriptor {}

/// Represents the layout of the resources and data that can be binded before drawing and that will
/// be accessible from the shaders.
///
/// The template parameter represents the descriptor sets.
// TODO: push constants.
pub struct PipelineLayout<P> {
    device: Arc<Device>,
    layout: VkPipelineLayout,
}

impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
    /// Creates a new `PipelineLayout`.
    pub fn new(device: &Arc<Device>) -> Result<Arc<PipelineLayout<L>>, > {
        let layout = unsafe {
            let infos = VkPipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: ,
                pSetLayouts: ,
                pushConstantRangeCount: ,
                pPushConstantRanges: ,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreatePipelineLayout(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(PipelineLayout {
            device: device.clone(),
            layout: layout,
        }))
    }
}

pub unsafe trait DescriptorSetDef {
    type Content;

}

// example:
// impl DescriptorSetDef for MyDescriptorSet { }

pub struct DescriptorSetLayout<D> {
    device: Arc<Device>,
    layout: vk::DescriptorSetLayout,
    marker: PhantomData<D>,
}

impl<D> DescriptorSetLayout<D> where D: DescriptorSetDef {
    pub fn new(device: &Arc<Device>) -> Result<Arc<DescriptorSetLayout<D>> {
        let vk = device.pointers();

        let bindings = ;

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(DescriptorSetLayout {
            device: device.clone(),
            layout: layout,
            marker: PhantomData,
        }))
    }
}

impl DescriptorSet {
    pub fn new<I>(device: &Arc<Device>, descriptors: I) -> Arc<DescriptorSet>
        where I: IntoIterator<Item = Descriptor>
    {
        let descriptors: Vec<_> = descriptors.into_iter().map(|descriptor| {
            let stage_flags =
                if descriptor.stages.vertex { vk::SHADER_STAGE_VERTEX_BIT } else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_TESSELLATION_CONTROL_BIT }
                else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_TESSELLATION_EVALUATION_BIT }
                else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_GEOMETRY_BIT } else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_FRAGMENT_BIT } else { 0 } |
                if descriptor.stages.vertex { vk::SHADER_STAGE_COMPUTE_BIT } else { 0 };

            // TODO: check array size limits

            VkDescriptorSetLayoutBinding {
                descriptorType: ,
                arraySize: descriptor.array_size,
                stageFlags: stage_flags,
                pImmutableSamplers: ,
            }
        }).collect();

        vkCreateDescriptorSetLayout
    }

    #[inline]
    pub fn write(&self) {
        DescriptorSet::update(Some(write), iter::empty())
    }

    #[inline]
    pub fn copy(&self) {
        DescriptorSet::update(iter::empty(), Some(copy))
    }

    #[inline]
    pub fn multi_write<I>(writes: I) {
        DescriptorSet::update(writes, iter::empty())
    }

    #[inline]
    pub fn multi_copy<I>(copies: I) {
        DescriptorSet::update(iter::empty(), copies)
    }

    pub fn update(writes: I, copies: J) {

    }
}

pub struct Descriptor {
    pub ty: DescriptorType,
    pub array_size: u32,
    pub stages: ShaderStages,
}

pub enum DescriptorType {
    Sampler,
    CombinedImageSampler,
    SampledImage,
    StorageImage,
    UniformTexelBuffer,
    StorageTexelBuffer,
    UniformBuffer,
    StorageBuffer,
    UniformBufferDynamic,
    StorageBufferDynamic,
    InputAttachment,
}

pub struct ShaderStages {
    pub vertex: bool,
    pub tessellation_control: bool,
    pub tessellation_evaluation: bool,
    pub geometry: bool,
    pub fragment: bool,
    pub compute: bool,
}
<|endoftext|>