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

#![allow(missing_copy_implementations)]

use fmt;
use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
use mem;

/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `reader` and then
/// write it into `writer` in a streaming fashion until `reader`
/// returns EOF.
///
/// On success, the total number of bytes that were copied from
/// `reader` to `writer` is returned.
///
/// # Errors
///
/// This function will return an error immediately if any call to `read` or
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
///
/// # Examples
///
/// ```
/// use std::io;
///
/// # fn foo() -> io::Result<()> {
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
/// io::copy(&mut reader, &mut writer)?;
///
/// assert_eq!(reader, &writer[..]);
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
    where R: Read, W: Write
{
    let mut buf = unsafe {
        let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
        reader.initializer().initialize(&mut buf);
        buf
    };

    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
    }
}

/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty`]. Please see
/// the documentation of [`empty()`][`empty`] for more details.
///
/// [`empty`]: fn.empty.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty { _priv: () }

/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// [`Ok`]: ../result/enum.Result.html#variant.Ok
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn empty() -> Empty { Empty { _priv: () } }

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
    #[inline]
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
    #[inline]
    fn consume(&mut self, _n: usize) {}
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Empty { .. }")
    }
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat`][repeat]. Please
/// see the documentation of `repeat()` for more details.
///
/// [repeat]: fn.repeat.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat { byte: u8 }

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for slot in &mut *buf {
            *slot = self.byte;
        }
        Ok(buf.len())
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Repeat { .. }")
    }
}

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`][sink]. Please
/// see the documentation of `sink()` for more details.
///
/// [sink]: fn.sink.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink { _priv: () }

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sink() -> Sink { Sink { _priv: () } }

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
    #[inline]
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Sink { .. }")
    }
}

#[cfg(test)]
mod tests {
    use io::prelude::*;
    use io::{copy, sink, empty, repeat};

    #[test]
    fn copy_copies() {
        let mut r = repeat(0).take(4);
        let mut w = sink();
        assert_eq!(copy(&mut r, &mut w).unwrap(), 4);

        let mut r = repeat(0).take(1 << 17);
        assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17);
    }

    #[test]
    fn sink_sinks() {
        let mut s = sink();
        assert_eq!(s.write(&[]).unwrap(), 0);
        assert_eq!(s.write(&[0]).unwrap(), 1);
        assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
        assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
    }

    #[test]
    fn empty_reads() {
        let mut e = empty();
        assert_eq!(e.read(&mut []).unwrap(), 0);
        assert_eq!(e.read(&mut [0]).unwrap(), 0);
        assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
        assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
    }

    #[test]
    fn repeat_repeats() {
        let mut r = repeat(4);
        let mut b = [0; 1024];
        assert_eq!(r.read(&mut b).unwrap(), 1024);
        assert!(b.iter().all(|b| *b == 4));
    }

    #[test]
    fn take_some_bytes() {
        assert_eq!(repeat(4).take(100).bytes().count(), 100);
        assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
        assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
    }
}
<commit_msg>Rollup merge of #44712 - oconnor663:copy_test, r=GuillaumeGomez<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(missing_copy_implementations)]

use fmt;
use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
use mem;

/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `reader` and then
/// write it into `writer` in a streaming fashion until `reader`
/// returns EOF.
///
/// On success, the total number of bytes that were copied from
/// `reader` to `writer` is returned.
///
/// # Errors
///
/// This function will return an error immediately if any call to `read` or
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
///
/// # Examples
///
/// ```
/// use std::io;
///
/// # fn foo() -> io::Result<()> {
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
/// io::copy(&mut reader, &mut writer)?;
///
/// assert_eq!(&b"hello"[..], &writer[..]);
/// # Ok(())
/// # }
/// # foo().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
    where R: Read, W: Write
{
    let mut buf = unsafe {
        let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
        reader.initializer().initialize(&mut buf);
        buf
    };

    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
    }
}

/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty`]. Please see
/// the documentation of [`empty()`][`empty`] for more details.
///
/// [`empty`]: fn.empty.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty { _priv: () }

/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// [`Ok`]: ../result/enum.Result.html#variant.Ok
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn empty() -> Empty { Empty { _priv: () } }

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
    #[inline]
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
    #[inline]
    fn consume(&mut self, _n: usize) {}
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Empty { .. }")
    }
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat`][repeat]. Please
/// see the documentation of `repeat()` for more details.
///
/// [repeat]: fn.repeat.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat { byte: u8 }

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for slot in &mut *buf {
            *slot = self.byte;
        }
        Ok(buf.len())
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Repeat { .. }")
    }
}

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`][sink]. Please
/// see the documentation of `sink()` for more details.
///
/// [sink]: fn.sink.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink { _priv: () }

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sink() -> Sink { Sink { _priv: () } }

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
    #[inline]
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Sink { .. }")
    }
}

#[cfg(test)]
mod tests {
    use io::prelude::*;
    use io::{copy, sink, empty, repeat};

    #[test]
    fn copy_copies() {
        let mut r = repeat(0).take(4);
        let mut w = sink();
        assert_eq!(copy(&mut r, &mut w).unwrap(), 4);

        let mut r = repeat(0).take(1 << 17);
        assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17);
    }

    #[test]
    fn sink_sinks() {
        let mut s = sink();
        assert_eq!(s.write(&[]).unwrap(), 0);
        assert_eq!(s.write(&[0]).unwrap(), 1);
        assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
        assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
    }

    #[test]
    fn empty_reads() {
        let mut e = empty();
        assert_eq!(e.read(&mut []).unwrap(), 0);
        assert_eq!(e.read(&mut [0]).unwrap(), 0);
        assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
        assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
    }

    #[test]
    fn repeat_repeats() {
        let mut r = repeat(4);
        let mut b = [0; 1024];
        assert_eq!(r.read(&mut b).unwrap(), 1024);
        assert!(b.iter().all(|b| *b == 4));
    }

    #[test]
    fn take_some_bytes() {
        assert_eq!(repeat(4).take(100).bytes().count(), 100);
        assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
        assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
    }
}
<|endoftext|>


<commit_before>use std::bigint::{ BigUint };

use common::problem::{ Problem };

pub static problem: Problem<'static> = Problem {
    id: 56,
    answer: "972",
    solver: solve
};

fn digit_sum(n: uint) -> uint {
    let mut sum = 0;
    let mut d = n;
    while d > 0 {
        sum += d % 10;
        d = d / 10;
    }
    return sum;
}

fn solve() -> ~str {
    let ten = BigUint::from_uint(1000000000);

    let mut max = 0u;
    for uint::range(1, 100) |a| {
        let mut n = BigUint::from_uint(a);
        for 100.times {
            n = n * BigUint::from_uint(a);
            let mut sum = 0;
            let mut (d, m) = n.divmod(&ten);
            sum += digit_sum(m.to_uint());
            while !d.is_zero() {
                let (d0, m) = d.divmod(&ten);
                sum += digit_sum(m.to_uint());
                d = d0;
            }
            // following core causes core dumps...
            // let s = n.to_str();
            // for str::each_char(s) |c| {
            //     let d = char::to_digit(c, 10);
            //     sum += d.get();
            // }
            max = uint::max(max, sum);
        }
    }

    return max.to_str();
}
<commit_msg>Follow bigint's method name change (divmod => div_mod)<commit_after>use std::bigint::{ BigUint };

use common::problem::{ Problem };

pub static problem: Problem<'static> = Problem {
    id: 56,
    answer: "972",
    solver: solve
};

fn digit_sum(n: uint) -> uint {
    let mut sum = 0;
    let mut d = n;
    while d > 0 {
        sum += d % 10;
        d = d / 10;
    }
    return sum;
}

fn solve() -> ~str {
    let ten = BigUint::from_uint(1000000000);

    let mut max = 0u;
    for uint::range(1, 100) |a| {
        let mut n = BigUint::from_uint(a);
        for 100.times {
            n = n * BigUint::from_uint(a);
            let mut sum = 0;
            let mut (d, m) = n.div_mod(&ten);
            sum += digit_sum(m.to_uint());
            while !d.is_zero() {
                let (d0, m) = d.div_mod(&ten);
                sum += digit_sum(m.to_uint());
                d = d0;
            }
            // following core causes core dumps...
            // let s = n.to_str();
            // for str::each_char(s) |c| {
            //     let d = char::to_digit(c, 10);
            //     sum += d.get();
            // }
            max = uint::max(max, sum);
        }
    }

    return max.to_str();
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

// Functions dealing with attributes and meta_items

use core::prelude::*;

use ast;
use codemap::{spanned, dummy_spanned};
use attr;
use codemap::BytePos;
use diagnostic::span_handler;
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};

use core::cmp;
use core::either::Either;
use core::either;
use core::option;
use core::vec;
use std::oldmap::HashMap;
use std::oldmap;
use std;

/* Constructors */

pub fn mk_name_value_item_str(name: ~str, value: ~str)
                           -> @ast::meta_item {
    let value_lit = dummy_spanned(ast::lit_str(@value));
    return mk_name_value_item(name, value_lit);
}

pub fn mk_name_value_item(name: ~str, +value: ast::lit)
        -> @ast::meta_item {
    return @dummy_spanned(ast::meta_name_value(name, value));
}

pub fn mk_list_item(name: ~str, +items: ~[@ast::meta_item]) ->
   @ast::meta_item {
    return @dummy_spanned(ast::meta_list(name, items));
}

pub fn mk_word_item(name: ~str) -> @ast::meta_item {
    return @dummy_spanned(ast::meta_word(name));
}

pub fn mk_attr(item: @ast::meta_item) -> ast::attribute {
    dummy_spanned(ast::attribute_ { style: ast::attr_inner,
                                    value: *item,
                                    is_sugared_doc: false })
}

pub fn mk_sugared_doc_attr(text: ~str,
                           +lo: BytePos, +hi: BytePos) -> ast::attribute {
    let lit = spanned(lo, hi, ast::lit_str(@text));
    let attr = ast::attribute_ {
        style: doc_comment_style(text),
        value: spanned(lo, hi, ast::meta_name_value(~"doc", lit)),
        is_sugared_doc: true
    };
    spanned(lo, hi, attr)
}

/* Conversion */

pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
    @attr.node.value
}

// Get the meta_items from inside a vector of attributes
pub fn attr_metas(attrs: ~[ast::attribute]) -> ~[@ast::meta_item] {
    do attrs.map |a| { attr_meta(*a) }
}

pub fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {
    if attr.node.is_sugared_doc {
        let comment = get_meta_item_value_str(@attr.node.value).get();
        let meta = mk_name_value_item_str(~"doc",
                                     strip_doc_comment_decoration(comment));
        return mk_attr(meta);
    } else {
        *attr
    }
}

/* Accessors */

pub fn get_attr_name(attr: ast::attribute) -> ~str {
    get_meta_item_name(@attr.node.value)
}

pub fn get_meta_item_name(meta: @ast::meta_item) -> ~str {
    match meta.node {
      ast::meta_word(ref n) => (*n),
      ast::meta_name_value(ref n, _) => (*n),
      ast::meta_list(ref n, _) => (*n)
    }
}

/**
 * Gets the string value if the meta_item is a meta_name_value variant
 * containing a string, otherwise none
 */
pub fn get_meta_item_value_str(meta: @ast::meta_item) -> Option<~str> {
    match meta.node {
        ast::meta_name_value(_, v) => match v.node {
            ast::lit_str(s) => option::Some(*s),
            _ => option::None
        },
        _ => option::None
    }
}

/// Gets a list of inner meta items from a list meta_item type
pub fn get_meta_item_list(meta: @ast::meta_item)
                       -> Option<~[@ast::meta_item]> {
    match meta.node {
      ast::meta_list(_, l) => option::Some(/* FIXME (#2543) */ copy l),
      _ => option::None
    }
}

/**
 * If the meta item is a nam-value type with a string value then returns
 * a tuple containing the name and string value, otherwise `none`
 */
pub fn get_name_value_str_pair(item: @ast::meta_item)
                            -> Option<(~str, ~str)> {
    match attr::get_meta_item_value_str(item) {
      Some(ref value) => {
        let name = attr::get_meta_item_name(item);
        Some((name, (*value)))
      }
      None => None
    }
}

/* Searching */

/// Search a list of attributes and return only those with a specific name
pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) ->
   ~[ast::attribute] {
    let filter: &fn(a: &ast::attribute) -> Option<ast::attribute> = |a| {
        if name == get_attr_name(*a) {
            option::Some(*a)
        } else {
            option::None
        }
    };
    return vec::filter_mapped(attrs, filter);
}

/// Search a list of meta items and return only those with a specific name
pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
   ~[@ast::meta_item] {
    let mut rs = ~[];
    for metas.each |mi| {
        if name == get_meta_item_name(*mi) {
            rs.push(*mi)
        }
    }
    rs
}

/**
 * Returns true if a list of meta items contains another meta item. The
 * comparison is performed structurally.
 */
pub fn contains(haystack: &[@ast::meta_item],
                needle: @ast::meta_item) -> bool {
    for haystack.each |item| {
        if eq(*item, needle) { return true; }
    }
    return false;
}

fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
    return match a.node {
          ast::meta_word(ref na) => match b.node {
            ast::meta_word(ref nb) => (*na) == (*nb),
            _ => false
          },
          ast::meta_name_value(ref na, va) => match b.node {
            ast::meta_name_value(ref nb, vb) => {
                (*na) == (*nb) && va.node == vb.node
            }
            _ => false
          },
          ast::meta_list(*) => {

            // ~[Fixme-sorting]
            // FIXME (#607): Needs implementing
            // This involves probably sorting the list by name and
            // meta_item variant
            die!(~"unimplemented meta_item variant")
          }
        }
}

pub fn contains_name(metas: &[@ast::meta_item], name: &str) -> bool {
    let matches = find_meta_items_by_name(metas, name);
    return vec::len(matches) > 0u;
}

pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
    !find_attrs_by_name(attrs, name).is_empty()
}

pub fn first_attr_value_str_by_name(attrs: ~[ast::attribute], name: ~str)
                                 -> Option<~str> {

    let mattrs = find_attrs_by_name(attrs, name);
    if vec::len(mattrs) > 0u {
        return get_meta_item_value_str(attr_meta(mattrs[0]));
    }
    return option::None;
}

fn last_meta_item_by_name(items: ~[@ast::meta_item], name: ~str)
    -> Option<@ast::meta_item> {

    let items = attr::find_meta_items_by_name(items, name);
    vec::last_opt(items)
}

pub fn last_meta_item_value_str_by_name(items: ~[@ast::meta_item], name: ~str)
                                     -> Option<~str> {

    match last_meta_item_by_name(items, name) {
      Some(item) => match attr::get_meta_item_value_str(item) {
        Some(ref value) => Some((*value)),
        None => None
      },
      None => None
    }
}

pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: ~str)
    -> Option<~[@ast::meta_item]> {

    match last_meta_item_by_name(items, name) {
      Some(item) => attr::get_meta_item_list(item),
      None => None
    }
}

/* Higher-level applications */

// FIXME (#607): This needs to sort by meta_item variant in addition to
// the item name (See [Fixme-sorting])
pub fn sort_meta_items(+items: ~[@ast::meta_item]) -> ~[@ast::meta_item] {
    pure fn lteq(ma: &@ast::meta_item, mb: &@ast::meta_item) -> bool {
        pure fn key(m: &ast::meta_item) -> ~str {
            match m.node {
              ast::meta_word(ref name) => (*name),
              ast::meta_name_value(ref name, _) => (*name),
              ast::meta_list(ref name, _) => (*name)
            }
        }
        key(*ma) <= key(*mb)
    }

    // This is sort of stupid here, converting to a vec of mutables and back
    let mut v: ~[@ast::meta_item] = items;
    std::sort::quick_sort(v, lteq);
    move v
}

pub fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: ~str) ->
   ~[@ast::meta_item] {

    return vec::filter_mapped(items, |item| {
        if get_meta_item_name(*item) != name {
            option::Some(*item)
        } else {
            option::None
        }
    });
}

/**
 * From a list of crate attributes get only the meta_items that affect crate
 * linkage
 */
pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
    do find_attrs_by_name(attrs, ~"link").flat_map |attr| {
        match attr.node.value.node {
            ast::meta_list(_, items) => /* FIXME (#2543) */ copy items,
            _ => ~[]
        }
    }
}

pub fn foreign_abi(attrs: ~[ast::attribute])
                -> Either<~str, ast::foreign_abi> {
    return match attr::first_attr_value_str_by_name(attrs, ~"abi") {
      option::None => {
        either::Right(ast::foreign_abi_cdecl)
      }
      option::Some(~"rust-intrinsic") => {
        either::Right(ast::foreign_abi_rust_intrinsic)
      }
      option::Some(~"cdecl") => {
        either::Right(ast::foreign_abi_cdecl)
      }
      option::Some(~"stdcall") => {
        either::Right(ast::foreign_abi_stdcall)
      }
      option::Some(ref t) => {
        either::Left(~"unsupported abi: " + (*t))
      }
    };
}

pub enum inline_attr {
    ia_none,
    ia_hint,
    ia_always,
    ia_never,
}

impl inline_attr : cmp::Eq {
    pure fn eq(&self, other: &inline_attr) -> bool {
        ((*self) as uint) == ((*other) as uint)
    }
    pure fn ne(&self, other: &inline_attr) -> bool { !(*self).eq(other) }
}

/// True if something like #[inline] is found in the list of attrs.
pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
    // FIXME (#2809)---validate the usage of #[inline] and #[inline(always)]
    do vec::foldl(ia_none, attrs) |ia,attr| {
        match attr.node.value.node {
          ast::meta_word(~"inline") => ia_hint,
          ast::meta_list(~"inline", items) => {
            if !vec::is_empty(find_meta_items_by_name(items, ~"always")) {
                ia_always
            } else if !vec::is_empty(
                find_meta_items_by_name(items, ~"never")) {
                ia_never
            } else {
                ia_hint
            }
          }
          _ => ia
        }
    }
}

pub fn require_unique_names(diagnostic: span_handler,
                            metas: &[@ast::meta_item]) {
    let map = oldmap::HashMap();
    for metas.each |meta| {
        let name = get_meta_item_name(*meta);

        // FIXME: How do I silence the warnings? --pcw (#2619)
        if map.contains_key(&name) {
            diagnostic.span_fatal(meta.span,
                                  fmt!("duplicate meta item `%s`", name));
        }
        map.insert(name, ());
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>libsyntax/attr.rs: switch from oldmap to LinearSet<commit_after>// Copyright 2012 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.

// Functions dealing with attributes and meta_items

use core::prelude::*;

use ast;
use codemap::{spanned, dummy_spanned};
use attr;
use codemap::BytePos;
use diagnostic::span_handler;
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};

use core::cmp;
use core::either::Either;
use core::either;
use core::option;
use core::vec;
use core::hashmap::linear::LinearSet;
use std;

/* Constructors */

pub fn mk_name_value_item_str(name: ~str, value: ~str)
                           -> @ast::meta_item {
    let value_lit = dummy_spanned(ast::lit_str(@value));
    return mk_name_value_item(name, value_lit);
}

pub fn mk_name_value_item(name: ~str, +value: ast::lit)
        -> @ast::meta_item {
    return @dummy_spanned(ast::meta_name_value(name, value));
}

pub fn mk_list_item(name: ~str, +items: ~[@ast::meta_item]) ->
   @ast::meta_item {
    return @dummy_spanned(ast::meta_list(name, items));
}

pub fn mk_word_item(name: ~str) -> @ast::meta_item {
    return @dummy_spanned(ast::meta_word(name));
}

pub fn mk_attr(item: @ast::meta_item) -> ast::attribute {
    dummy_spanned(ast::attribute_ { style: ast::attr_inner,
                                    value: *item,
                                    is_sugared_doc: false })
}

pub fn mk_sugared_doc_attr(text: ~str,
                           +lo: BytePos, +hi: BytePos) -> ast::attribute {
    let lit = spanned(lo, hi, ast::lit_str(@text));
    let attr = ast::attribute_ {
        style: doc_comment_style(text),
        value: spanned(lo, hi, ast::meta_name_value(~"doc", lit)),
        is_sugared_doc: true
    };
    spanned(lo, hi, attr)
}

/* Conversion */

pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
    @attr.node.value
}

// Get the meta_items from inside a vector of attributes
pub fn attr_metas(attrs: ~[ast::attribute]) -> ~[@ast::meta_item] {
    do attrs.map |a| { attr_meta(*a) }
}

pub fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {
    if attr.node.is_sugared_doc {
        let comment = get_meta_item_value_str(@attr.node.value).get();
        let meta = mk_name_value_item_str(~"doc",
                                     strip_doc_comment_decoration(comment));
        return mk_attr(meta);
    } else {
        *attr
    }
}

/* Accessors */

pub fn get_attr_name(attr: ast::attribute) -> ~str {
    get_meta_item_name(@attr.node.value)
}

pub fn get_meta_item_name(meta: @ast::meta_item) -> ~str {
    match meta.node {
      ast::meta_word(ref n) => (*n),
      ast::meta_name_value(ref n, _) => (*n),
      ast::meta_list(ref n, _) => (*n)
    }
}

/**
 * Gets the string value if the meta_item is a meta_name_value variant
 * containing a string, otherwise none
 */
pub fn get_meta_item_value_str(meta: @ast::meta_item) -> Option<~str> {
    match meta.node {
        ast::meta_name_value(_, v) => match v.node {
            ast::lit_str(s) => option::Some(*s),
            _ => option::None
        },
        _ => option::None
    }
}

/// Gets a list of inner meta items from a list meta_item type
pub fn get_meta_item_list(meta: @ast::meta_item)
                       -> Option<~[@ast::meta_item]> {
    match meta.node {
      ast::meta_list(_, l) => option::Some(/* FIXME (#2543) */ copy l),
      _ => option::None
    }
}

/**
 * If the meta item is a nam-value type with a string value then returns
 * a tuple containing the name and string value, otherwise `none`
 */
pub fn get_name_value_str_pair(item: @ast::meta_item)
                            -> Option<(~str, ~str)> {
    match attr::get_meta_item_value_str(item) {
      Some(ref value) => {
        let name = attr::get_meta_item_name(item);
        Some((name, (*value)))
      }
      None => None
    }
}

/* Searching */

/// Search a list of attributes and return only those with a specific name
pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) ->
   ~[ast::attribute] {
    let filter: &fn(a: &ast::attribute) -> Option<ast::attribute> = |a| {
        if name == get_attr_name(*a) {
            option::Some(*a)
        } else {
            option::None
        }
    };
    return vec::filter_mapped(attrs, filter);
}

/// Search a list of meta items and return only those with a specific name
pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
   ~[@ast::meta_item] {
    let mut rs = ~[];
    for metas.each |mi| {
        if name == get_meta_item_name(*mi) {
            rs.push(*mi)
        }
    }
    rs
}

/**
 * Returns true if a list of meta items contains another meta item. The
 * comparison is performed structurally.
 */
pub fn contains(haystack: &[@ast::meta_item],
                needle: @ast::meta_item) -> bool {
    for haystack.each |item| {
        if eq(*item, needle) { return true; }
    }
    return false;
}

fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
    return match a.node {
          ast::meta_word(ref na) => match b.node {
            ast::meta_word(ref nb) => (*na) == (*nb),
            _ => false
          },
          ast::meta_name_value(ref na, va) => match b.node {
            ast::meta_name_value(ref nb, vb) => {
                (*na) == (*nb) && va.node == vb.node
            }
            _ => false
          },
          ast::meta_list(*) => {

            // ~[Fixme-sorting]
            // FIXME (#607): Needs implementing
            // This involves probably sorting the list by name and
            // meta_item variant
            die!(~"unimplemented meta_item variant")
          }
        }
}

pub fn contains_name(metas: &[@ast::meta_item], name: &str) -> bool {
    let matches = find_meta_items_by_name(metas, name);
    return vec::len(matches) > 0u;
}

pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
    !find_attrs_by_name(attrs, name).is_empty()
}

pub fn first_attr_value_str_by_name(attrs: ~[ast::attribute], name: ~str)
                                 -> Option<~str> {

    let mattrs = find_attrs_by_name(attrs, name);
    if vec::len(mattrs) > 0u {
        return get_meta_item_value_str(attr_meta(mattrs[0]));
    }
    return option::None;
}

fn last_meta_item_by_name(items: ~[@ast::meta_item], name: ~str)
    -> Option<@ast::meta_item> {

    let items = attr::find_meta_items_by_name(items, name);
    vec::last_opt(items)
}

pub fn last_meta_item_value_str_by_name(items: ~[@ast::meta_item], name: ~str)
                                     -> Option<~str> {

    match last_meta_item_by_name(items, name) {
      Some(item) => match attr::get_meta_item_value_str(item) {
        Some(ref value) => Some((*value)),
        None => None
      },
      None => None
    }
}

pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: ~str)
    -> Option<~[@ast::meta_item]> {

    match last_meta_item_by_name(items, name) {
      Some(item) => attr::get_meta_item_list(item),
      None => None
    }
}

/* Higher-level applications */

// FIXME (#607): This needs to sort by meta_item variant in addition to
// the item name (See [Fixme-sorting])
pub fn sort_meta_items(+items: ~[@ast::meta_item]) -> ~[@ast::meta_item] {
    pure fn lteq(ma: &@ast::meta_item, mb: &@ast::meta_item) -> bool {
        pure fn key(m: &ast::meta_item) -> ~str {
            match m.node {
              ast::meta_word(ref name) => (*name),
              ast::meta_name_value(ref name, _) => (*name),
              ast::meta_list(ref name, _) => (*name)
            }
        }
        key(*ma) <= key(*mb)
    }

    // This is sort of stupid here, converting to a vec of mutables and back
    let mut v: ~[@ast::meta_item] = items;
    std::sort::quick_sort(v, lteq);
    move v
}

pub fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: ~str) ->
   ~[@ast::meta_item] {

    return vec::filter_mapped(items, |item| {
        if get_meta_item_name(*item) != name {
            option::Some(*item)
        } else {
            option::None
        }
    });
}

/**
 * From a list of crate attributes get only the meta_items that affect crate
 * linkage
 */
pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
    do find_attrs_by_name(attrs, ~"link").flat_map |attr| {
        match attr.node.value.node {
            ast::meta_list(_, items) => /* FIXME (#2543) */ copy items,
            _ => ~[]
        }
    }
}

pub fn foreign_abi(attrs: ~[ast::attribute])
                -> Either<~str, ast::foreign_abi> {
    return match attr::first_attr_value_str_by_name(attrs, ~"abi") {
      option::None => {
        either::Right(ast::foreign_abi_cdecl)
      }
      option::Some(~"rust-intrinsic") => {
        either::Right(ast::foreign_abi_rust_intrinsic)
      }
      option::Some(~"cdecl") => {
        either::Right(ast::foreign_abi_cdecl)
      }
      option::Some(~"stdcall") => {
        either::Right(ast::foreign_abi_stdcall)
      }
      option::Some(ref t) => {
        either::Left(~"unsupported abi: " + (*t))
      }
    };
}

pub enum inline_attr {
    ia_none,
    ia_hint,
    ia_always,
    ia_never,
}

impl inline_attr : cmp::Eq {
    pure fn eq(&self, other: &inline_attr) -> bool {
        ((*self) as uint) == ((*other) as uint)
    }
    pure fn ne(&self, other: &inline_attr) -> bool { !(*self).eq(other) }
}

/// True if something like #[inline] is found in the list of attrs.
pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
    // FIXME (#2809)---validate the usage of #[inline] and #[inline(always)]
    do vec::foldl(ia_none, attrs) |ia,attr| {
        match attr.node.value.node {
          ast::meta_word(~"inline") => ia_hint,
          ast::meta_list(~"inline", items) => {
            if !vec::is_empty(find_meta_items_by_name(items, ~"always")) {
                ia_always
            } else if !vec::is_empty(
                find_meta_items_by_name(items, ~"never")) {
                ia_never
            } else {
                ia_hint
            }
          }
          _ => ia
        }
    }
}

pub fn require_unique_names(diagnostic: span_handler,
                            metas: &[@ast::meta_item]) {
    let mut set = LinearSet::new();
    for metas.each |meta| {
        let name = get_meta_item_name(*meta);

        // FIXME: How do I silence the warnings? --pcw (#2619)
        if !set.insert(name) {
            diagnostic.span_fatal(meta.span,
                                  fmt!("duplicate meta item `%s`", name));
        }
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>pub struct Block<'a> {
  pub is_last: bool,
  pub length: u32,
  pub data: BlockData<'a>,
}

pub enum BlockData<'a> {
  StreamInfo(StreamInfo<'a>),
  Padding(u32),
  Application(Application<'a>),
  SeekTable(Vec<SeekPoint>),
  VorbisComment(VorbisComment<'a>),
  CueSheet(CueSheet<'a>),
  Picture(Picture<'a>),
  Unknown(&'a [u8]),
}

pub struct StreamInfo<'a> {
  pub min_block_size: u16,
  pub max_block_size: u16,
  pub min_frame_size: u32,
  pub max_frame_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub bits_per_sample: u8,
  pub total_samples: u64,
  pub md5_sum: &'a [u8],
}

pub struct Application<'a> {
  pub id: &'a str,
  pub data: &'a [u8],
}

pub struct SeekPoint {
  pub sample_number: u64,
  pub stream_offset: u64,
  pub frame_samples: u16,
}

pub struct VorbisComment<'a> {
  pub vendor_string: &'a str,
  pub comments: Vec<&'a str>,
}

pub struct CueSheet<'a> {
  pub media_catalog_number: &'a str,
  pub lead_in: u64,
  pub is_cd: bool,
  pub tracks: Vec<CueSheetTrack<'a>>,
}

pub struct CueSheetTrack<'a> {
  pub offset: u64,
  pub number: u8,
  pub isrc: &'a str,
  pub isnt_audio: bool,
  pub is_pre_emphasis: bool,
  pub indices: Vec<CueSheetTrackIndex>,
}

pub struct CueSheetTrackIndex {
  pub offset: u64,
  pub number: u8,
}

pub struct Picture<'a> {
  pub picture_type: PictureType,
  pub mime_type: &'a str,
  pub description: &'a str,
  pub width: u32,
  pub height: u32,
  pub depth: u32,
  pub colors: u32,
  pub data: &'a [u8],
}

pub enum PictureType {
  Other,
  FileIconStandard,
  FileIcon,
  FrontCover,
  BackCover,
  LeafletPage,
  Media,
  LeadArtist,
  Artist,
  Conductor,
  Band,
  Composer,
  Lyricist,
  RecordingLocation,
  DuringRecording,
  DuringPerformace,
  VideoScreenCapture,
  Fish,
  Illustration,
  BandLogoType,
  PublisherLogoType,
}
<commit_msg>Add information about each BlockData type<commit_after>pub struct Block<'a> {
  pub is_last: bool,
  pub length: u32,
  pub data: BlockData<'a>,
}

pub enum BlockData<'a> {
  StreamInfo(StreamInfo<'a>),
  Padding(u32),
  Application(Application<'a>),
  SeekTable(Vec<SeekPoint>),
  VorbisComment(VorbisComment<'a>),
  CueSheet(CueSheet<'a>),
  Picture(Picture<'a>),
  Unknown(&'a [u8]),
}

/// Information regarding the entire audio stream
pub struct StreamInfo<'a> {
  pub min_block_size: u16,
  pub max_block_size: u16,
  pub min_frame_size: u32,
  pub max_frame_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub bits_per_sample: u8,
  pub total_samples: u64,
  pub md5_sum: &'a [u8],
}

/// Data used by third-party applications
pub struct Application<'a> {
  pub id: &'a str,
  pub data: &'a [u8],
}

/// Seek, or skip, to a point within the FLAC file
pub struct SeekPoint {
  pub sample_number: u64,
  pub stream_offset: u64,
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs
pub struct VorbisComment<'a> {
  pub vendor_string: &'a str,
  pub comments: Vec<&'a str>,
}

/// Stores cue information
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
pub struct CueSheet<'a> {
  pub media_catalog_number: &'a str,
  pub lead_in: u64,
  pub is_cd: bool,
  pub tracks: Vec<CueSheetTrack<'a>>,
}

pub struct CueSheetTrack<'a> {
  pub offset: u64,
  pub number: u8,
  pub isrc: &'a str,
  pub isnt_audio: bool,
  pub is_pre_emphasis: bool,
  pub indices: Vec<CueSheetTrackIndex>,
}

pub struct CueSheetTrackIndex {
  pub offset: u64,
  pub number: u8,
}

/// Stores pictures associated with a FLAC file
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
pub struct Picture<'a> {
  pub picture_type: PictureType,
  pub mime_type: &'a str,
  pub description: &'a str,
  pub width: u32,
  pub height: u32,
  pub depth: u32,
  pub colors: u32,
  pub data: &'a [u8],
}

pub enum PictureType {
  Other,
  FileIconStandard,
  FileIcon,
  FrontCover,
  BackCover,
  LeafletPage,
  Media,
  LeadArtist,
  Artist,
  Conductor,
  Band,
  Composer,
  Lyricist,
  RecordingLocation,
  DuringRecording,
  DuringPerformace,
  VideoScreenCapture,
  Fish,
  Illustration,
  BandLogoType,
  PublisherLogoType,
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ptr;

// We should use {u32,u64}::BYTES when they are stable;
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

/// Converts a slice of bytes into an iterator of u32. The data is
/// always treated as little endian!
// FIXME: Probably doesn't work on big endian machines.
struct U32FromBytes<'a> {
    start: *const u32,
    end: *const u32,
    marker: PhantomData<&'a ()>
}

impl<'a> U32FromBytes<'a> {
    /// Returns the iterator and any left-over bytes.
    fn new(bytes: &'a [u8]) -> (U32FromBytes<'a>, &'a [u8]) {
        let full_chunks = bytes.len() / U32_BYTES;
        let (mine, theirs) = bytes.split_at(full_chunks * U32_BYTES);

        let start = mine.as_ptr() as *const u32;
        let end = unsafe { start.offset(full_chunks as isize) };

        let me = U32FromBytes {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for U32FromBytes<'a> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        if self.start >= self.end { return None }

        let v: u32 = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }
}

/// Converts a slice of bytes into an iterator of u64. The data is
/// always treated as little endian!
// FIXME: Probably doesn't work on big endian machines.
struct U64FromBytes<'a> {
    start: *const u64,
    end: *const u64,
    marker: PhantomData<&'a ()>
}

impl<'a> U64FromBytes<'a> {
    /// Returns the iterator and any left-over bytes.
    fn new(bytes: &'a [u8]) -> (U64FromBytes<'a>, &'a [u8]) {
        let full_chunks = bytes.len() / U64_BYTES;
        let (mine, theirs) = bytes.split_at(full_chunks * U64_BYTES);

        let start = mine.as_ptr() as *const u64;
        let end = unsafe { start.offset(full_chunks as isize) };

        let me = U64FromBytes {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for U64FromBytes<'a> {
    type Item = u64;

    fn next(&mut self) -> Option<u64> {
        if self.start >= self.end { return None }

        let v: u64 = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }
}

pub trait NumberStreams {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]);
    fn u64_stream(&self) -> (U64FromBytes, &[u8]);
}

impl<'a> NumberStreams for [u8] {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]) { U32FromBytes::new(self) }
    fn u64_stream(&self) -> (U64FromBytes, &[u8]) { U64FromBytes::new(self) }
}

#[cfg(test)]
mod test {
    use ::std::slice;
    use super::{U32FromBytes,U32_BYTES};
    use super::{U64FromBytes,U64_BYTES};

    fn u32_slice_as_u8(values: &[u32]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U32_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u32_from_bytes() {
        let orig_values: &[u32] = &[0,1];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = U32FromBytes::new(as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u32_from_bytes_with_leftovers() {
        let orig_values: &[u32] = &[0,1];
        let mut as_u8: Vec<_> = u32_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = U32FromBytes::new(&as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    fn u64_slice_as_u8(values: &[u64]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U64_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u64_from_bytes() {
        let orig_values: &[u64] = &[0,1];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = U64FromBytes::new(as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u64_from_bytes_with_leftovers() {
        let orig_values: &[u64] = &[0,1];
        let mut as_u8: Vec<_> = u64_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = U64FromBytes::new(&as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }
}
<commit_msg>DRY up the number streams with a macro<commit_after>use std::marker::PhantomData;
use std::ptr;

// We should use {u32,u64}::BYTES when they are stable;
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

macro_rules! number_stream(
    ($name:ident, $number_type:ty, $bytes_in_type:expr) => (
struct $name<'a> {
    start: *const $number_type,
    end: *const $number_type,
    marker: PhantomData<&'a ()>
}

impl<'a> $name<'a> {
    fn new(bytes: &'a [u8]) -> ($name<'a>, &'a [u8]) {
        let full_chunks = bytes.len() / $bytes_in_type;
        let (mine, theirs) = bytes.split_at(full_chunks * $bytes_in_type);

        let start = mine.as_ptr() as *const $number_type;
        let end = unsafe { start.offset(full_chunks as isize) };

        let me = $name {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for $name<'a> {
    type Item = $number_type;

    fn next(&mut self) -> Option<$number_type> {
        if self.start >= self.end { return None }

        let v: $number_type = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }
}
));

number_stream!(U32FromBytes, u32, U32_BYTES);
number_stream!(U64FromBytes, u64, U64_BYTES);

/// Converts a slice of bytes into an iterator of numbers.
///
/// The data is always treated as little endian. Only complete ranges
/// of bytes are parsed as the number, any left-over bytes are returned.
// FIXME: Probably doesn't work on big endian machines.
pub trait NumberStreams {
    /// Reads u32s from the bytes
    fn u32_stream(&self) -> (U32FromBytes, &[u8]);
    /// Reads u64s from the bytes
    fn u64_stream(&self) -> (U64FromBytes, &[u8]);
}

impl<'a> NumberStreams for [u8] {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]) { U32FromBytes::new(self) }
    fn u64_stream(&self) -> (U64FromBytes, &[u8]) { U64FromBytes::new(self) }
}

#[cfg(test)]
mod test {
    use ::std::slice;
    use super::{U32FromBytes,U32_BYTES};
    use super::{U64FromBytes,U64_BYTES};

    fn u32_slice_as_u8(values: &[u32]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U32_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u32_from_bytes() {
        let orig_values: &[u32] = &[0,1];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = U32FromBytes::new(as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u32_from_bytes_with_leftovers() {
        let orig_values: &[u32] = &[0,1];
        let mut as_u8: Vec<_> = u32_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = U32FromBytes::new(&as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    fn u64_slice_as_u8(values: &[u64]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U64_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u64_from_bytes() {
        let orig_values: &[u64] = &[0,1];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = U64FromBytes::new(as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u64_from_bytes_with_leftovers() {
        let orig_values: &[u64] = &[0,1];
        let mut as_u8: Vec<_> = u64_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = U64FromBytes::new(&as_u8);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }
}
<|endoftext|>


<commit_before>use super::{read_uint, write_uint, ByMode, BySpeed, GameId, Mode, Record, Speed, ByUci};
use byteorder::{ReadBytesExt as _, WriteBytesExt as _};
use std::cmp::min;
use std::io::{self, Read, Write};
use std::ops::AddAssign;

const MAX_GAMES: usize = 15; // 4 bits

#[derive(Debug, Eq, PartialEq)]
enum Header {
    Group {
        mode: Mode,
        speed: Speed,
        num_games: usize,
    },
    End,
}

impl Record for Header {
    fn read<R: Read>(reader: &mut R) -> io::Result<Header> {
        let n = reader.read_u8()?;
        Ok(Header::Group {
            speed: match n & 7 {
                0 => return Ok(Header::End),
                1 => Speed::Ultrabullet,
                2 => Speed::Bullet,
                3 => Speed::Blitz,
                4 => Speed::Rapid,
                5 => Speed::Classical,
                6 => Speed::Correspondence,
                _ => return Err(io::ErrorKind::InvalidData.into()),
            },
            mode: Mode::from_rated((n >> 3) & 1 == 1),
            num_games: usize::from(n >> 4),
        })
    }

    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u8(match *self {
            Header::End => 0,
            Header::Group {
                mode,
                speed,
                num_games,
            } => {
                (match speed {
                    Speed::Ultrabullet => 1,
                    Speed::Bullet => 2,
                    Speed::Blitz => 3,
                    Speed::Rapid => 4,
                    Speed::Classical => 5,
                    Speed::Correspondence => 6,
                }) | ((mode.is_rated() as u8) << 3)
                    | ((num_games as u8) << 4)
            }
        })
    }
}

#[derive(Debug, Default)]
struct Stats {
    white: u64,
    draw: u64,
    black: u64,
}

impl AddAssign for Stats {
    fn add_assign(&mut self, rhs: Stats) {
        self.white += rhs.white;
        self.draw += rhs.draw;
        self.black += rhs.black;
    }
}

impl Record for Stats {
    fn read<R: Read>(reader: &mut R) -> io::Result<Stats> {
        Ok(Stats {
            white: read_uint(reader)?,
            draw: read_uint(reader)?,
            black: read_uint(reader)?,
        })
    }

    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        write_uint(writer, self.white)?;
        write_uint(writer, self.draw)?;
        write_uint(writer, self.black)
    }
}

#[derive(Default)]
struct Group {
    stats: Stats,
    games: Vec<(u8, GameId)>,
}

#[derive(Default)]
struct PersonalRecord {
    inner: BySpeed<ByMode<Group>>,
}

impl Record for PersonalRecord {
    fn read<R: Read>(reader: &mut R) -> io::Result<PersonalRecord> {
        let mut acc = PersonalRecord::default();
        loop {
            match Header::read(reader)? {
                Header::Group {
                    speed,
                    mode,
                    num_games,
                } => {
                    let stats = Stats::read(reader)?;
                    let mut games = Vec::with_capacity(num_games);
                    for _ in 0..num_games {
                        let game_idx = reader.read_u8()?;
                        let game = GameId::read(reader)?;
                        games.push((game_idx, game));
                    }
                    let group = acc.inner.by_speed_mut(speed).by_mode_mut(mode);
                    *group = Group { stats, games };
                }
                Header::End => break,
            }
        }
        Ok(acc)
    }

    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        self.inner.as_ref().try_map(|speed, by_mode| {
            by_mode.as_ref().try_map(|mode, group| {
                let num_games = min(group.games.len(), MAX_GAMES);

                Header::Group {
                    speed,
                    mode,
                    num_games,
                }
                .write(writer)?;

                group.stats.write(writer)?;

                for (game_idx, game) in group.games.iter().take(num_games) {
                    writer.write_u8(*game_idx)?;
                    game.write(writer)?;
                }

                Ok::<_, io::Error>(())
            })
        })?;

        Header::End.write(writer)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn test_header_roundtrip() {
        let headers = [
            Header::Group {
                mode: Mode::Rated,
                speed: Speed::Correspondence,
                num_games: 15,
            },
            Header::End,
        ];

        let mut writer = Cursor::new(Vec::new());
        for header in &headers {
            header.write(&mut writer).unwrap();
        }

        let mut reader = Cursor::new(writer.into_inner());
        for header in headers {
            assert_eq!(Header::read(&mut reader).unwrap(), header);
        }
    }
}
<commit_msg>keep max game idx for each sub record<commit_after>use super::{read_uint, write_uint, ByMode, BySpeed, GameId, Mode, Record, Speed, ByUci};
use byteorder::{ReadBytesExt as _, WriteBytesExt as _};
use std::cmp::min;
use std::io::{self, Read, Write};
use std::ops::AddAssign;
use std::cmp::max;

const MAX_GAMES: usize = 15; // 4 bits

#[derive(Debug, Eq, PartialEq)]
enum Header {
    Group {
        mode: Mode,
        speed: Speed,
        num_games: usize,
    },
    End,
}

impl Record for Header {
    fn read<R: Read>(reader: &mut R) -> io::Result<Header> {
        let n = reader.read_u8()?;
        Ok(Header::Group {
            speed: match n & 7 {
                0 => return Ok(Header::End),
                1 => Speed::Ultrabullet,
                2 => Speed::Bullet,
                3 => Speed::Blitz,
                4 => Speed::Rapid,
                5 => Speed::Classical,
                6 => Speed::Correspondence,
                _ => return Err(io::ErrorKind::InvalidData.into()),
            },
            mode: Mode::from_rated((n >> 3) & 1 == 1),
            num_games: usize::from(n >> 4),
        })
    }

    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u8(match *self {
            Header::End => 0,
            Header::Group {
                mode,
                speed,
                num_games,
            } => {
                (match speed {
                    Speed::Ultrabullet => 1,
                    Speed::Bullet => 2,
                    Speed::Blitz => 3,
                    Speed::Rapid => 4,
                    Speed::Classical => 5,
                    Speed::Correspondence => 6,
                }) | ((mode.is_rated() as u8) << 3)
                    | ((num_games as u8) << 4)
            }
        })
    }
}

#[derive(Debug, Default)]
struct Stats {
    white: u64,
    draw: u64,
    black: u64,
}

impl AddAssign for Stats {
    fn add_assign(&mut self, rhs: Stats) {
        self.white += rhs.white;
        self.draw += rhs.draw;
        self.black += rhs.black;
    }
}

impl Record for Stats {
    fn read<R: Read>(reader: &mut R) -> io::Result<Stats> {
        Ok(Stats {
            white: read_uint(reader)?,
            draw: read_uint(reader)?,
            black: read_uint(reader)?,
        })
    }

    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        write_uint(writer, self.white)?;
        write_uint(writer, self.draw)?;
        write_uint(writer, self.black)
    }
}

#[derive(Default)]
struct Group {
    stats: Stats,
    games: Vec<(u8, GameId)>,
}

#[derive(Default)]
struct SubRecord {
    inner: BySpeed<ByMode<Group>>,
    max_game_idx: u8,
}

impl Record for SubRecord {
    fn read<R: Read>(reader: &mut R) -> io::Result<SubRecord> {
        let mut acc = SubRecord::default();
        loop {
            match Header::read(reader)? {
                Header::Group {
                    speed,
                    mode,
                    num_games,
                } => {
                    let stats = Stats::read(reader)?;
                    let mut games = Vec::with_capacity(num_games);
                    for _ in 0..num_games {
                        let game_idx = reader.read_u8()?;
                        acc.max_game_idx = max(acc.max_game_idx, game_idx);
                        let game = GameId::read(reader)?;
                        games.push((game_idx, game));
                    }
                    let group = acc.inner.by_speed_mut(speed).by_mode_mut(mode);
                    *group = Group { stats, games };
                }
                Header::End => break,
            }
        }
        Ok(acc)
    }

    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        self.inner.as_ref().try_map(|speed, by_mode| {
            by_mode.as_ref().try_map(|mode, group| {
                let num_games = min(group.games.len(), MAX_GAMES);

                Header::Group {
                    speed,
                    mode,
                    num_games,
                }
                .write(writer)?;

                group.stats.write(writer)?;

                for (game_idx, game) in group.games.iter().take(num_games) {
                    writer.write_u8(*game_idx)?;
                    game.write(writer)?;
                }

                Ok::<_, io::Error>(())
            })
        })?;

        Header::End.write(writer)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn test_header_roundtrip() {
        let headers = [
            Header::Group {
                mode: Mode::Rated,
                speed: Speed::Correspondence,
                num_games: 15,
            },
            Header::End,
        ];

        let mut writer = Cursor::new(Vec::new());
        for header in &headers {
            header.write(&mut writer).unwrap();
        }

        let mut reader = Cursor::new(writer.into_inner());
        for header in headers {
            assert_eq!(Header::read(&mut reader).unwrap(), header);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate mimir;
extern crate osmpbfreader;

use ::admin_geofinder::AdminGeoFinder;
use ::boundaries::{build_boundary, make_centroid};
use std::collections::{BTreeSet, BTreeMap};
use super::utils::*;
use super::OsmPbfReader;

pub type PoiTypes = BTreeMap<String, BTreeSet<String>>;
pub type PoisVec = Vec<mimir::Poi>;

#[derive(Debug)]
struct PoiMatcher {
    poi_types: PoiTypes,
}

impl PoiMatcher {
    pub fn new(types: PoiTypes) -> PoiMatcher {
        PoiMatcher { poi_types: types }
    }

    pub fn is_poi(&self, obj: &osmpbfreader::OsmObj) -> bool {
        self.poi_types.iter().any(|(poi_tag, poi_types)| {
            obj.tags().get(poi_tag).map_or(false, |poi_type| poi_types.contains(poi_type))
        })
    }
}

pub fn default_osm_amenity_types_read() -> BTreeSet<String> {
    ["university",
     "hospital",
     "post_office",
     "bicycle_rental",
     "bicycle_parking",
     "parking",
     "police",
     "townhall"]
        .iter()
        .map(|&k| k.to_string())
        .collect()
}

pub fn default_osm_leisure_types_read() -> BTreeSet<String> {
    ["garden", "park"]
        .iter()
        .map(|&k| k.to_string())
        .collect()
}

fn parse_poi(osmobj: &osmpbfreader::OsmObj,
             obj_map: &BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>,
             admins_geofinder: &AdminGeoFinder,
             city_level: u32)
             -> Option<mimir::Poi> {
    let (id, coord) = match *osmobj {
        osmpbfreader::OsmObj::Node(ref node) => {
            (format_poi_id("node", node.id), mimir::Coord::new(node.lat, node.lon))
        }
        osmpbfreader::OsmObj::Way(ref way) => {
            (format_poi_id("way", way.id), get_way_coord(obj_map, way))
        }
        osmpbfreader::OsmObj::Relation(ref relation) => {
            (format_poi_id("relation", relation.id),
             make_centroid(&build_boundary(&relation, &obj_map)))
        }
    };

    let name = osmobj.tags().get("name").map_or(osmobj.tags().get("amenity"), |name| Some(name) );

    if coord.is_default() {
        info!("The poi {} is rejected, cause: could not compute coordinates.",
              id);
        return None;
    }

    let name = if let Some(s) = name {
    	s
    } else {
        info!("The poi {} is rejected, cause: could not compute name.", id);
        return None;
    };

    let adms = admins_geofinder.get(&coord);
    let zip_codes = match osmobj.tags().get("addr:postcode") {
        Some(val) if !val.is_empty() => vec![val.clone()],
        _ => get_zip_codes_from_admins(&adms),
    };
    Some(mimir::Poi {
        id: id,
        name: name.to_string(),
        label: format_label(&adms, city_level, name),
        coord: coord,
        zip_codes: zip_codes,
        administrative_regions: adms,
        weight: 1,
    })
}

fn format_poi_id(_type: &str, id: i64) -> String {
    format!("poi:osm:{}:{}", _type, id)
}

pub fn pois(pbf: &mut OsmPbfReader,
            poi_types: PoiTypes,
            admins_geofinder: &AdminGeoFinder,
            city_level: u32)
            -> PoisVec {
    let matcher = PoiMatcher::new(poi_types);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_poi(o)).unwrap();
    objects.iter()
        .filter(|&(_, obj)| matcher.is_poi(&obj))
        .filter_map(|(_, obj)| parse_poi(obj, &objects, admins_geofinder, city_level))
        .collect()
}

pub fn compute_poi_weight(pois_vec: &mut PoisVec, city_level: u32) {
    for poi in pois_vec {
        for admin in &mut poi.administrative_regions {
            if admin.level == city_level {
                poi.weight = admin.weight.get();
                break;
            }
        }
    }
}
<commit_msg>mimirsbrunn: apply fmt<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate mimir;
extern crate osmpbfreader;

use ::admin_geofinder::AdminGeoFinder;
use ::boundaries::{build_boundary, make_centroid};
use std::collections::{BTreeSet, BTreeMap};
use super::utils::*;
use super::OsmPbfReader;

pub type PoiTypes = BTreeMap<String, BTreeSet<String>>;
pub type PoisVec = Vec<mimir::Poi>;

#[derive(Debug)]
struct PoiMatcher {
    poi_types: PoiTypes,
}

impl PoiMatcher {
    pub fn new(types: PoiTypes) -> PoiMatcher {
        PoiMatcher { poi_types: types }
    }

    pub fn is_poi(&self, obj: &osmpbfreader::OsmObj) -> bool {
        self.poi_types.iter().any(|(poi_tag, poi_types)| {
            obj.tags().get(poi_tag).map_or(false, |poi_type| poi_types.contains(poi_type))
        })
    }
}

pub fn default_osm_amenity_types_read() -> BTreeSet<String> {
    ["university",
     "hospital",
     "post_office",
     "bicycle_rental",
     "bicycle_parking",
     "parking",
     "police",
     "townhall"]
        .iter()
        .map(|&k| k.to_string())
        .collect()
}

pub fn default_osm_leisure_types_read() -> BTreeSet<String> {
    ["garden", "park"]
        .iter()
        .map(|&k| k.to_string())
        .collect()
}

fn parse_poi(osmobj: &osmpbfreader::OsmObj,
             obj_map: &BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>,
             admins_geofinder: &AdminGeoFinder,
             city_level: u32)
             -> Option<mimir::Poi> {
    let (id, coord) = match *osmobj {
        osmpbfreader::OsmObj::Node(ref node) => {
            (format_poi_id("node", node.id), mimir::Coord::new(node.lat, node.lon))
        }
        osmpbfreader::OsmObj::Way(ref way) => {
            (format_poi_id("way", way.id), get_way_coord(obj_map, way))
        }
        osmpbfreader::OsmObj::Relation(ref relation) => {
            (format_poi_id("relation", relation.id),
             make_centroid(&build_boundary(&relation, &obj_map)))
        }
    };

    let name = osmobj.tags().get("name").map_or(osmobj.tags().get("amenity"), |name| Some(name));

    if coord.is_default() {
        info!("The poi {} is rejected, cause: could not compute coordinates.",
              id);
        return None;
    }

    let name = if let Some(s) = name {
        s
    } else {
        info!("The poi {} is rejected, cause: could not compute name.", id);
        return None;
    };

    let adms = admins_geofinder.get(&coord);
    let zip_codes = match osmobj.tags().get("addr:postcode") {
        Some(val) if !val.is_empty() => vec![val.clone()],
        _ => get_zip_codes_from_admins(&adms),
    };
    Some(mimir::Poi {
        id: id,
        name: name.to_string(),
        label: format_label(&adms, city_level, name),
        coord: coord,
        zip_codes: zip_codes,
        administrative_regions: adms,
        weight: 1,
    })
}

fn format_poi_id(_type: &str, id: i64) -> String {
    format!("poi:osm:{}:{}", _type, id)
}

pub fn pois(pbf: &mut OsmPbfReader,
            poi_types: PoiTypes,
            admins_geofinder: &AdminGeoFinder,
            city_level: u32)
            -> PoisVec {
    let matcher = PoiMatcher::new(poi_types);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_poi(o)).unwrap();
    objects.iter()
        .filter(|&(_, obj)| matcher.is_poi(&obj))
        .filter_map(|(_, obj)| parse_poi(obj, &objects, admins_geofinder, city_level))
        .collect()
}

pub fn compute_poi_weight(pois_vec: &mut PoisVec, city_level: u32) {
    for poi in pois_vec {
        for admin in &mut poi.administrative_regions {
            if admin.level == city_level {
                poi.weight = admin.weight.get();
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "dylib"]
#![feature(plugin_registrar, quote, globs)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use rustc::plugin::Registry;
use std::io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box expand_peg_str, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box expand_peg_file, None));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case_functions, unused_variable)]
    let attr = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec!(
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    )));

    MacItems::new(Some(cx.item_mod(sp, sp, ident, vec!(attr), ast.view_items.clone(), ast.items.clone())).into_iter())
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::EOF) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<commit_msg>Make Cargo rebuild when a peg_file! source file is modified.<commit_after>#![crate_type = "dylib"]
#![feature(plugin_registrar, quote, globs)]

extern crate rustc;
extern crate syntax;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItems, DummyResult};
use syntax::parse;
use syntax::parse::token;
use syntax::fold::Folder;
use rustc::plugin::Registry;
use std::io::fs::File;
use std::str;

use rustast::{AstBuilder, DUMMY_SP};

mod translate;
mod grammar;
mod rustast;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            token::intern("peg"),
            syntax::ext::base::IdentTT(box expand_peg_str, None));

    reg.register_syntax_extension(
            token::intern("peg_file"),
            syntax::ext::base::IdentTT(box expand_peg_file, None));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, tts.as_slice()) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<ast::TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, tts.as_slice()) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(cx.codemap().span_to_filename(sp)).dir_path().join(fname);

    let source_utf8 = match File::open(&path).read_to_end() {
      Ok(source_utf8) => source_utf8,
      Err(e) => {
        cx.span_err(sp, e.to_string().as_slice());
        return DummyResult::any(sp)
      }
    };

    let source = str::from_utf8(source_utf8.as_slice()).unwrap();

    cx.codemap().new_filemap(path.as_str().unwrap().to_string(), "".to_string());

    expand_peg(cx, sp, ident, source.as_slice())
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let grammar_def = grammar::grammar(source);

    let grammar_def = match grammar_def {
      Ok(grammar_def) => grammar_def,
      Err(msg) => {
        cx.span_err(sp, msg.as_slice());
        return DummyResult::any(sp)
      }
    };

    let ast = translate::compile_grammar(cx, &grammar_def);

    // #![allow(non_snake_case_functions, unused_variable)]
    let attr = cx.attribute(DUMMY_SP, cx.meta_list(DUMMY_SP, token::InternedString::new("allow"), vec!(
        cx.meta_word(DUMMY_SP, token::InternedString::new("non_snake_case")),
        cx.meta_word(DUMMY_SP, token::InternedString::new("unused")),
    )));

    MacItems::new(Some(cx.item_mod(sp, sp, ident, vec!(attr), ast.view_items.clone(), ast.items.clone())).into_iter())
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(parser.parse_expr());
    match arg.node {
        ast::ExprLit(ref spanned) => {
            match spanned.node {
                ast::LitStr(ref n, _) => {
                    if !parser.eat(&token::EOF) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.get().to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, err.as_slice());
    None
}
<|endoftext|>