<commit_before>//! Sources of points.
//!
//! These don't necessarily have to be file format readers, but they usually are.

pub mod las;
pub mod sdc;
#[cfg(feature = "rxp-source")]
pub mod rxp;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;

use las::Reader as LasReader;
#[cfg(feature = "rxp-source")]
use rivlib::Stream as RxpStream;
use rustc_serialize::Decodable;
use toml;

use Result;
use error::Error;
use point::Point;

enum SourceType {
    Las,
    #[cfg(feature = "rxp-source")]
    Rxp,
}

impl SourceType {
    fn from_osstr_ref<S: AsRef<OsStr>>(s: S) -> Result<SourceType> {
        match Path::new(&s).extension().and_then(|e| e.to_str()) {
            Some("las") => Ok(SourceType::Las),
            #[cfg(feature = "rxp-source")]
            Some("rxp") => Ok(SourceType::Rxp),
            Some(_) | None => Err(Error::UnregisteredFileExtension(OsStr::new(&s).to_os_string())),
        }
    }
}

macro_rules! decode_or_default {
    ($klass:path, $decoder:expr) => {{
        match $decoder {
            Some(ref mut decoder) => try!(<$klass as FileSource>::Config::decode(decoder)),
            None => Default::default()
        }
    }}
}

/// Opens a file source with the given options.
///
/// # Examples
///
/// ```
/// use pabst::source::open_file_source;
/// let source = open_file_source("data/1.0_0.las", None).unwrap();
/// ```
pub fn open_file_source<P>(path: P, config: Option<toml::Value>) -> Result<Box<Source>> where P: AsRef<Path> + AsRef<OsStr>
{
    let mut decoder = config.map(|c| toml::Decoder::new(c));
    match try!(SourceType::from_osstr_ref(&path)) {
        SourceType::Las => LasReader::<BufReader<File>>::open_file_source(path, decode_or_default!(LasReader<BufReader<File>>, decoder)),
        #[cfg(feature = "rxp-source")]
        SourceType::Rxp => RxpStream::open_file_source(path, decode_or_default!(RxpStream, decoder)),
    }
}

/// A point source.
pub trait Source {
    /// Sources some points from the `Source`.
    ///
    /// Use `want` to request a certain number of points, but the source is not compelled to return
    /// exactly that number. This method returns an optional vector of points, or `None` if the
    /// source is out of points.
    fn source(&mut self, want: usize) -> Result<Option<Vec<Point>>>;

    /// Sources all points in this `Source`.
    ///
    /// If the source is an infinite stream, it should re-define this method to return an error.
    fn source_to_end(&mut self, want: usize) -> Result<Vec<Point>> {
        let mut points = Vec::new();
        loop {
            match try!(self.source(want)) {
                Some(ref mut p) => points.append(p),
                None => return Ok(points),
            }
        }
    }

    /// Returns a guess at total number of points in this source.
    ///
    /// If possible, sources should prefer to report point totals from headers, etc, rather than
    /// reading all of the points. For this reason, users of this method should be aware that it
    /// might not be exactly correct.
    ///
    /// Sources that cannot know their point count should return `None`.
    fn source_len(&mut self) -> Option<usize>;
}

/// A point source that can be opened from a path.
pub trait FileSource {
    /// Decodable configuration object.
    type Config: Decodable;

    /// Opens a file source with the given config.
    fn open_file_source<P>(path: P, config: Self::Config) -> Result<Box<Source>> where P: AsRef<Path> + AsRef<OsStr>;
}
<commit_msg>Implement source for box source<commit_after>//! Sources of points.
//!
//! These don't necessarily have to be file format readers, but they usually are.

pub mod las;
pub mod sdc;
#[cfg(feature = "rxp-source")]
pub mod rxp;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;

use las::Reader as LasReader;
#[cfg(feature = "rxp-source")]
use rivlib::Stream as RxpStream;
use rustc_serialize::Decodable;
use toml;

use Result;
use error::Error;
use point::Point;

enum SourceType {
    Las,
    #[cfg(feature = "rxp-source")]
    Rxp,
}

impl SourceType {
    fn from_osstr_ref<S: AsRef<OsStr>>(s: S) -> Result<SourceType> {
        match Path::new(&s).extension().and_then(|e| e.to_str()) {
            Some("las") => Ok(SourceType::Las),
            #[cfg(feature = "rxp-source")]
            Some("rxp") => Ok(SourceType::Rxp),
            Some(_) | None => Err(Error::UnregisteredFileExtension(OsStr::new(&s).to_os_string())),
        }
    }
}

macro_rules! decode_or_default {
    ($klass:path, $decoder:expr) => {{
        match $decoder {
            Some(ref mut decoder) => try!(<$klass as FileSource>::Config::decode(decoder)),
            None => Default::default()
        }
    }}
}

/// Opens a file source with the given options.
///
/// # Examples
///
/// ```
/// use pabst::source::open_file_source;
/// let source = open_file_source("data/1.0_0.las", None).unwrap();
/// ```
pub fn open_file_source<P>(path: P, config: Option<toml::Value>) -> Result<Box<Source>> where P: AsRef<Path> + AsRef<OsStr>
{
    let mut decoder = config.map(|c| toml::Decoder::new(c));
    match try!(SourceType::from_osstr_ref(&path)) {
        SourceType::Las => LasReader::<BufReader<File>>::open_file_source(path, decode_or_default!(LasReader<BufReader<File>>, decoder)),
        #[cfg(feature = "rxp-source")]
        SourceType::Rxp => RxpStream::open_file_source(path, decode_or_default!(RxpStream, decoder)),
    }
}

/// A point source.
pub trait Source {
    /// Sources some points from the `Source`.
    ///
    /// Use `want` to request a certain number of points, but the source is not compelled to return
    /// exactly that number. This method returns an optional vector of points, or `None` if the
    /// source is out of points.
    fn source(&mut self, want: usize) -> Result<Option<Vec<Point>>>;

    /// Sources all points in this `Source`.
    ///
    /// If the source is an infinite stream, it should re-define this method to return an error.
    fn source_to_end(&mut self, want: usize) -> Result<Vec<Point>> {
        let mut points = Vec::new();
        loop {
            match try!(self.source(want)) {
                Some(ref mut p) => points.append(p),
                None => return Ok(points),
            }
        }
    }

    /// Returns a guess at total number of points in this source.
    ///
    /// If possible, sources should prefer to report point totals from headers, etc, rather than
    /// reading all of the points. For this reason, users of this method should be aware that it
    /// might not be exactly correct.
    ///
    /// Sources that cannot know their point count should return `None`.
    fn source_len(&mut self) -> Option<usize>;
}

impl Source for Box<Source> {
    fn source(&mut self, want: usize) -> Result<Option<Vec<Point>>> {
        (**self).source(want)
    }

    fn source_len(&mut self) -> Option<usize> {
        (**self).source_len()
    }
}

/// A point source that can be opened from a path.
pub trait FileSource {
    /// Decodable configuration object.
    type Config: Decodable;

    /// Opens a file source with the given config.
    fn open_file_source<P>(path: P, config: Self::Config) -> Result<Box<Source>> where P: AsRef<Path> + AsRef<OsStr>;
}
<|endoftext|>


<commit_before>extern crate raindrops;

#[test]
fn test_1() { assert_eq!("1", raindrops::raindrops(1)); }

#[test]
fn test_3() { assert_eq!("Pling", raindrops::raindrops(3)); }

#[test]
fn test_5() { assert_eq!("Plang", raindrops::raindrops(5)); }

#[test]
fn test_7() { assert_eq!("Plong", raindrops::raindrops(7)); }

#[test]
fn test_6() { assert_eq!("Pling", raindrops::raindrops(6)); }

#[test]
fn test_9() { assert_eq!("Pling", raindrops::raindrops(9)); }

#[test]
#[ignore]
fn test_10() { assert_eq!("Plang", raindrops::raindrops(10)); }

#[test]
#[ignore]
fn test_14() { assert_eq!("Plong", raindrops::raindrops(14)); }

#[test]
#[ignore]
fn test_15() { assert_eq!("PlingPlang", raindrops::raindrops(15)); }

#[test]
#[ignore]
fn test_21() { assert_eq!("PlingPlong", raindrops::raindrops(21)); }

#[test]
#[ignore]
fn test_25() { assert_eq!("Plang", raindrops::raindrops(25)); }

#[test]
#[ignore]
fn test_35() { assert_eq!("PlangPlong", raindrops::raindrops(35)); }

#[test]
#[ignore]
fn test_49() { assert_eq!("Plong", raindrops::raindrops(49)); }

#[test]
#[ignore]
fn test_52() { assert_eq!("52", raindrops::raindrops(52)); }

#[test]
#[ignore]
fn test_105() { assert_eq!("PlingPlangPlong", raindrops::raindrops(105)); }

#[test]
#[ignore]
fn test_12121() { assert_eq!("12121", raindrops::raindrops(12121)); }
<commit_msg>all cases where single-worded output is needed for low numbers covered<commit_after>extern crate raindrops;

#[test]
fn test_1() { assert_eq!("1", raindrops::raindrops(1)); }

#[test]
fn test_3() { assert_eq!("Pling", raindrops::raindrops(3)); }

#[test]
fn test_5() { assert_eq!("Plang", raindrops::raindrops(5)); }

#[test]
fn test_7() { assert_eq!("Plong", raindrops::raindrops(7)); }

#[test]
fn test_6() { assert_eq!("Pling", raindrops::raindrops(6)); }

#[test]
fn test_9() { assert_eq!("Pling", raindrops::raindrops(9)); }

#[test]
fn test_10() { assert_eq!("Plang", raindrops::raindrops(10)); }

#[test]
fn test_14() { assert_eq!("Plong", raindrops::raindrops(14)); }

#[test]
#[ignore]
fn test_15() { assert_eq!("PlingPlang", raindrops::raindrops(15)); }

#[test]
#[ignore]
fn test_21() { assert_eq!("PlingPlong", raindrops::raindrops(21)); }

#[test]
#[ignore]
fn test_25() { assert_eq!("Plang", raindrops::raindrops(25)); }

#[test]
#[ignore]
fn test_35() { assert_eq!("PlangPlong", raindrops::raindrops(35)); }

#[test]
#[ignore]
fn test_49() { assert_eq!("Plong", raindrops::raindrops(49)); }

#[test]
#[ignore]
fn test_52() { assert_eq!("52", raindrops::raindrops(52)); }

#[test]
#[ignore]
fn test_105() { assert_eq!("PlingPlangPlong", raindrops::raindrops(105)); }

#[test]
#[ignore]
fn test_12121() { assert_eq!("12121", raindrops::raindrops(12121)); }
<|endoftext|>


<commit_before>use super::Blob;
use failure::Error;
use futures::Future;
use rusoto_core::region::Region;
use rusoto_credential::DefaultCredentialsProvider;
use rusoto_s3::{GetObjectRequest, PutObjectRequest, S3Client, S3};
use std::convert::TryInto;
use std::io::Read;
use time::Timespec;
use log::{error, warn};

pub(crate) struct S3Backend<'a> {
    client: S3Client,
    bucket: &'a str,
}

impl<'a> S3Backend<'a> {
    pub(crate) fn new(client: S3Client, bucket: &'a str) -> Self {
        Self { client, bucket }
    }

    pub(super) fn get(&self, path: &str) -> Result<Blob, Error> {
        let res = self
            .client
            .get_object(GetObjectRequest {
                bucket: self.bucket.to_string(),
                key: path.into(),
                ..Default::default()
            })
            .sync()?;

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::with_capacity(
            res.content_length
                .and_then(|l| l.try_into().ok())
                .unwrap_or(0),
        );
        b.read_to_end(&mut content).unwrap();

        let date_updated = parse_timespec(&res.last_modified.unwrap())?;

        Ok(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated,
            content,
        })
    }

    pub(super) fn store_batch(&self, batch: &[Blob]) -> Result<(), Error> {
        let mut rt = tokio::runtime::Runtime::new().unwrap();
        let mut attempts = 0;

        loop {
            let mut futures = Vec::with_capacity(batch.len());
            for blob in batch {
                futures.push(
                    self.client
                        .put_object(PutObjectRequest {
                            bucket: self.bucket.to_string(),
                            key: blob.path.clone(),
                            body: Some(blob.content.clone().into()),
                            content_type: Some(blob.mime.clone()),
                            ..Default::default()
                        })
                        .inspect(|_| {
                            crate::web::metrics::UPLOADED_FILES_TOTAL.inc_by(1);
                        }),
                );
            }
            attempts += 1;

            match rt.block_on(::futures::future::join_all(futures)) {
                // this batch was successful, start another batch if there are still more files
                Ok(_) => break,
                Err(err) => {
                    error!("failed to upload to s3: {:?}", err);
                    // if a futures error occurs, retry the batch
                    if attempts > 2 {
                        panic!("failed to upload 3 times, exiting");
                    }
                }
            }
        }
        Ok(())
    }
}

// public for testing
pub(crate) const TIME_FMT: &str = "%a, %d %b %Y %H:%M:%S %Z";

fn parse_timespec(raw: &str) -> Result<Timespec, Error> {
    Ok(time::strptime(raw, TIME_FMT)?.to_timespec())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test::TestEnvironment;

    fn assert_s3_404(env: &TestEnvironment, path: &'static str) {
        use rusoto_core::RusotoError;
        use rusoto_s3::GetObjectError;

        let s3 = env.s3().not_found(path);
        let backend = S3Backend::new(s3.client, s3.bucket);
        let err = backend.get(path).unwrap_err();
        let status = match err
            .downcast_ref::<RusotoError<GetObjectError>>()
            .expect("wanted GetObject")
        {
            RusotoError::Unknown(http) => http.status,
            _ => panic!("wrong error"),
        };
        assert_eq!(status, 404);
    }

    #[test]
    fn test_parse_timespec() {
        crate::test::wrapper(|_| {
            // Test valid conversions
            assert_eq!(
                parse_timespec("Thu, 1 Jan 1970 00:00:00 GMT")?,
                Timespec::new(0, 0)
            );
            assert_eq!(
                parse_timespec("Mon, 16 Apr 2018 04:33:50 GMT")?,
                Timespec::new(1523853230, 0)
            );

            // Test invalid conversion
            assert!(parse_timespec("foo").is_err());

            Ok(())
        })
    }

    #[test]
    fn test_path_get() {
        crate::test::wrapper(|env| {
            let blob = Blob {
                path: "dir/foo.txt".into(),
                mime: "text/plain".into(),
                date_updated: Timespec::new(42, 0),
                content: "Hello world!".into(),
            };

            // Add a test file to the database
            let s3 = env.s3().upload(blob.clone());

            let backend = S3Backend::new(s3.client, &s3.bucket);

            // Test that the proper file was returned
            assert_eq!(blob, backend.get("dir/foo.txt")?);

            // Test that other files are not returned
            assert_s3_404(&env, "dir/bar.txt");
            assert_s3_404(&env, "foo.txt");

            Ok(())
        });
    }
}

pub(crate) static S3_BUCKET_NAME: &str = "rust-docs-rs";

pub(crate) fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() && std::env::var_os("FORCE_S3").is_none() {
        return None;
    }
    let creds = match DefaultCredentialsProvider::new() {
        Ok(creds) => creds,
        Err(err) => {
            warn!("failed to retrieve AWS credentials: {}", err);
            return None;
        }
    };
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        creds,
        std::env::var("S3_ENDPOINT")
            .ok()
            .map(|e| Region::Custom {
                name: std::env::var("S3_REGION").unwrap_or_else(|_| "us-west-1".to_owned()),
                endpoint: e,
            })
            .unwrap_or(Region::UsWest1),
    ))
}
<commit_msg>haha rustfmt go brrr<commit_after>use super::Blob;
use failure::Error;
use futures::Future;
use log::{error, warn};
use rusoto_core::region::Region;
use rusoto_credential::DefaultCredentialsProvider;
use rusoto_s3::{GetObjectRequest, PutObjectRequest, S3Client, S3};
use std::convert::TryInto;
use std::io::Read;
use time::Timespec;

pub(crate) struct S3Backend<'a> {
    client: S3Client,
    bucket: &'a str,
}

impl<'a> S3Backend<'a> {
    pub(crate) fn new(client: S3Client, bucket: &'a str) -> Self {
        Self { client, bucket }
    }

    pub(super) fn get(&self, path: &str) -> Result<Blob, Error> {
        let res = self
            .client
            .get_object(GetObjectRequest {
                bucket: self.bucket.to_string(),
                key: path.into(),
                ..Default::default()
            })
            .sync()?;

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::with_capacity(
            res.content_length
                .and_then(|l| l.try_into().ok())
                .unwrap_or(0),
        );
        b.read_to_end(&mut content).unwrap();

        let date_updated = parse_timespec(&res.last_modified.unwrap())?;

        Ok(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated,
            content,
        })
    }

    pub(super) fn store_batch(&self, batch: &[Blob]) -> Result<(), Error> {
        let mut rt = tokio::runtime::Runtime::new().unwrap();
        let mut attempts = 0;

        loop {
            let mut futures = Vec::with_capacity(batch.len());
            for blob in batch {
                futures.push(
                    self.client
                        .put_object(PutObjectRequest {
                            bucket: self.bucket.to_string(),
                            key: blob.path.clone(),
                            body: Some(blob.content.clone().into()),
                            content_type: Some(blob.mime.clone()),
                            ..Default::default()
                        })
                        .inspect(|_| {
                            crate::web::metrics::UPLOADED_FILES_TOTAL.inc_by(1);
                        }),
                );
            }
            attempts += 1;

            match rt.block_on(::futures::future::join_all(futures)) {
                // this batch was successful, start another batch if there are still more files
                Ok(_) => break,
                Err(err) => {
                    error!("failed to upload to s3: {:?}", err);
                    // if a futures error occurs, retry the batch
                    if attempts > 2 {
                        panic!("failed to upload 3 times, exiting");
                    }
                }
            }
        }
        Ok(())
    }
}

// public for testing
pub(crate) const TIME_FMT: &str = "%a, %d %b %Y %H:%M:%S %Z";

fn parse_timespec(raw: &str) -> Result<Timespec, Error> {
    Ok(time::strptime(raw, TIME_FMT)?.to_timespec())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test::TestEnvironment;

    fn assert_s3_404(env: &TestEnvironment, path: &'static str) {
        use rusoto_core::RusotoError;
        use rusoto_s3::GetObjectError;

        let s3 = env.s3().not_found(path);
        let backend = S3Backend::new(s3.client, s3.bucket);
        let err = backend.get(path).unwrap_err();
        let status = match err
            .downcast_ref::<RusotoError<GetObjectError>>()
            .expect("wanted GetObject")
        {
            RusotoError::Unknown(http) => http.status,
            _ => panic!("wrong error"),
        };
        assert_eq!(status, 404);
    }

    #[test]
    fn test_parse_timespec() {
        crate::test::wrapper(|_| {
            // Test valid conversions
            assert_eq!(
                parse_timespec("Thu, 1 Jan 1970 00:00:00 GMT")?,
                Timespec::new(0, 0)
            );
            assert_eq!(
                parse_timespec("Mon, 16 Apr 2018 04:33:50 GMT")?,
                Timespec::new(1523853230, 0)
            );

            // Test invalid conversion
            assert!(parse_timespec("foo").is_err());

            Ok(())
        })
    }

    #[test]
    fn test_path_get() {
        crate::test::wrapper(|env| {
            let blob = Blob {
                path: "dir/foo.txt".into(),
                mime: "text/plain".into(),
                date_updated: Timespec::new(42, 0),
                content: "Hello world!".into(),
            };

            // Add a test file to the database
            let s3 = env.s3().upload(blob.clone());

            let backend = S3Backend::new(s3.client, &s3.bucket);

            // Test that the proper file was returned
            assert_eq!(blob, backend.get("dir/foo.txt")?);

            // Test that other files are not returned
            assert_s3_404(&env, "dir/bar.txt");
            assert_s3_404(&env, "foo.txt");

            Ok(())
        });
    }
}

pub(crate) static S3_BUCKET_NAME: &str = "rust-docs-rs";

pub(crate) fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() && std::env::var_os("FORCE_S3").is_none() {
        return None;
    }
    let creds = match DefaultCredentialsProvider::new() {
        Ok(creds) => creds,
        Err(err) => {
            warn!("failed to retrieve AWS credentials: {}", err);
            return None;
        }
    };
    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        creds,
        std::env::var("S3_ENDPOINT")
            .ok()
            .map(|e| Region::Custom {
                name: std::env::var("S3_REGION").unwrap_or_else(|_| "us-west-1".to_owned()),
                endpoint: e,
            })
            .unwrap_or(Region::UsWest1),
    ))
}
<|endoftext|>


<commit_before>use std::{
    future::Future,
    pin::Pin,
    sync::{
        atomic::{AtomicBool, Ordering::Relaxed},
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
    },
    task::{Context, Poll, Waker},
    time::{Duration, Instant},
};

use crate::*;

static ID_GEN: AtomicUsize = AtomicUsize::new(0);

/// An event that happened to a key that a subscriber is interested in.
#[derive(Debug, Clone)]
pub struct Event {
    /// A map of batches for each tree written to in a transaction,
    /// only one of which will be the one subscribed to.
    pub(crate) batches: Arc<[(Tree, Batch)]>,
}

impl Event {
    pub(crate) fn single_update(
        tree: Tree,
        key: IVec,
        value: Option<IVec>,
    ) -> Event {
        Event::single_batch(
            tree,
            Batch { writes: vec![(key, value)].into_iter().collect() },
        )
    }

    pub(crate) fn single_batch(tree: Tree, batch: Batch) -> Event {
        Event::from_batches(vec![(tree, batch)])
    }

    pub(crate) fn from_batches(batches: Vec<(Tree, Batch)>) -> Event {
        Event { batches: Arc::from(batches.into_boxed_slice()) }
    }

    /// Iterate over each Tree, key, and optional value in this `Event`
    pub fn iter<'a>(
        &'a self,
    ) -> Box<dyn 'a + Iterator<Item = (&'a Tree, &'a IVec, &'a Option<IVec>)>>
    {
        self.into_iter()
    }
}

impl<'a> IntoIterator for &'a Event {
    type Item = (&'a Tree, &'a IVec, &'a Option<IVec>);
    type IntoIter = Box<dyn 'a + Iterator<Item = Self::Item>>;

    fn into_iter(self) -> Self::IntoIter {
        Box::new(self.batches.iter().flat_map(|(ref tree, ref batch)| {
            batch.writes.iter().map(move |(k, v_opt)| (tree, k, v_opt))
        }))
    }
}

type Senders = Map<usize, (Option<Waker>, SyncSender<OneShot<Option<Event>>>)>;

/// A subscriber listening on a specified prefix
///
/// `Subscriber` implements both `Iterator<Item = Event>`
/// and `Future<Output=Option<Event>>`
///
/// # Examples
///
/// Synchronous, blocking subscriber:
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use sled::{Config, Event};
/// let config = Config::new().temporary(true);
///
/// let tree = config.open()?;
///
/// // watch all events by subscribing to the empty prefix
/// let mut subscriber = tree.watch_prefix(vec![]);
///
/// let tree_2 = tree.clone();
/// let thread = std::thread::spawn(move || {
///     tree.insert(vec![0], vec![1])
/// });
///
/// // `Subscription` implements `Iterator<Item=Event>`
/// for event in subscriber.take(1) {
///     match event {
///         Event::Insert{ key, value } => assert_eq!(key.as_ref(), &[0]),
///         Event::Remove {key } => {}
///     }
/// }
///
/// # thread.join().unwrap();
/// # Ok(())
/// # }
/// ```
/// Aynchronous, non-blocking subscriber:
///
/// `Subscription` implements `Future<Output=Option<Event>>`.
///
/// `while let Some(event) = (&mut subscriber).await { /* use it */ }`
pub struct Subscriber {
    id: usize,
    rx: Receiver<OneShot<Option<Event>>>,
    home: Arc<RwLock<Senders>>,
}

impl Drop for Subscriber {
    fn drop(&mut self) {
        let mut w_senders = self.home.write();
        w_senders.remove(&self.id);
    }
}

impl Subscriber {
    /// Attempts to wait for a value on this `Subscriber`, returning
    /// an error if no event arrives within the provided `Duration`
    /// or if the backing `Db` shuts down.
    pub fn next_timeout(
        &self,
        mut timeout: Duration,
    ) -> std::result::Result<Event, std::sync::mpsc::RecvTimeoutError> {
        loop {
            let start = Instant::now();
            let future_rx = self.rx.recv_timeout(timeout)?;
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };

            let start = Instant::now();
            if let Some(event) = future_rx.wait_timeout(timeout)? {
                return Ok(event);
            }
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };
        }
    }
}

impl Future for Subscriber {
    type Output = Option<Event>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.rx.try_recv() {
                Ok(mut future_rx) => {
                    #[allow(unsafe_code)]
                    let future_rx =
                        unsafe { std::pin::Pin::new_unchecked(&mut future_rx) };

                    match Future::poll(future_rx, cx) {
                        Poll::Ready(Some(event)) => {
                            return Poll::Ready(event);
                        }
                        Poll::Ready(None) => {
                            continue;
                        }
                        Poll::Pending => {
                            return Poll::Pending;
                        }
                    }
                }
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => return Poll::Ready(None),
            }
        }
        let mut home = self.home.write();
        let entry = home.get_mut(&self.id).unwrap();
        entry.0 = Some(cx.waker().clone());
        Poll::Pending
    }
}

impl Iterator for Subscriber {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        loop {
            let future_rx = self.rx.recv().ok()?;
            match future_rx.wait() {
                Some(Some(event)) => return Some(event),
                Some(None) => return None,
                None => continue,
            }
        }
    }
}

#[derive(Debug, Default)]
pub(crate) struct Subscribers {
    watched: RwLock<BTreeMap<Vec<u8>, Arc<RwLock<Senders>>>>,
    ever_used: AtomicBool,
}

impl Drop for Subscribers {
    fn drop(&mut self) {
        let watched = self.watched.read();

        for senders in watched.values() {
            let senders =
                std::mem::replace(&mut *senders.write(), Map::default());
            for (_, (waker, sender)) in senders {
                drop(sender);
                if let Some(waker) = waker {
                    waker.wake();
                }
            }
        }
    }
}

impl Subscribers {
    pub(crate) fn register(&self, prefix: &[u8]) -> Subscriber {
        self.ever_used.store(true, Relaxed);
        let r_mu = {
            let r_mu = self.watched.read();
            if r_mu.contains_key(prefix) {
                r_mu
            } else {
                drop(r_mu);
                let mut w_mu = self.watched.write();
                if !w_mu.contains_key(prefix) {
                    let old = w_mu.insert(
                        prefix.to_vec(),
                        Arc::new(RwLock::new(Map::default())),
                    );
                    assert!(old.is_none());
                }
                drop(w_mu);
                self.watched.read()
            }
        };

        let (tx, rx) = sync_channel(1024);

        let arc_senders = &r_mu[prefix];
        let mut w_senders = arc_senders.write();

        let id = ID_GEN.fetch_add(1, Relaxed);

        w_senders.insert(id, (None, tx));

        Subscriber { id, rx, home: arc_senders.clone() }
    }

    pub(crate) fn reserve_batch(
        &self,
        batch: &Batch,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();

        let mut skip_indices = std::collections::HashSet::new();
        let mut subscribers = vec![];

        for key in batch.writes.keys() {
            for (idx, (prefix, subs_rwl)) in r_mu.iter().enumerate() {
                if key.starts_with(prefix) && !skip_indices.contains(&idx) {
                    skip_indices.insert(idx);
                    let subs = subs_rwl.read();

                    for (_id, (waker, sender)) in subs.iter() {
                        let (tx, rx) = OneShot::pair();
                        if sender.send(rx).is_err() {
                            continue;
                        }
                        subscribers.push((waker.clone(), tx));
                    }
                }
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }

    pub(crate) fn reserve<R: AsRef<[u8]>>(
        &self,
        key: R,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();
        let prefixes = r_mu.iter().filter(|(k, _)| key.as_ref().starts_with(k));

        let mut subscribers = vec![];

        for (_, subs_rwl) in prefixes {
            let subs = subs_rwl.read();

            for (_id, (waker, sender)) in subs.iter() {
                let (tx, rx) = OneShot::pair();
                if sender.send(rx).is_err() {
                    continue;
                }
                subscribers.push((waker.clone(), tx));
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }
}

pub(crate) struct ReservedBroadcast {
    subscribers: Vec<(Option<Waker>, OneShotFiller<Option<Event>>)>,
}

impl ReservedBroadcast {
    pub fn complete(self, event: &Event) {
        let iter = self.subscribers.into_iter();

        for (waker, tx) in iter {
            tx.fill(Some(event.clone()));
            if let Some(waker) = waker {
                waker.wake();
            }
        }
    }
}
<commit_msg>Fix subscriber doctest<commit_after>use std::{
    future::Future,
    pin::Pin,
    sync::{
        atomic::{AtomicBool, Ordering::Relaxed},
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
    },
    task::{Context, Poll, Waker},
    time::{Duration, Instant},
};

use crate::*;

static ID_GEN: AtomicUsize = AtomicUsize::new(0);

/// An event that happened to a key that a subscriber is interested in.
#[derive(Debug, Clone)]
pub struct Event {
    /// A map of batches for each tree written to in a transaction,
    /// only one of which will be the one subscribed to.
    pub(crate) batches: Arc<[(Tree, Batch)]>,
}

impl Event {
    pub(crate) fn single_update(
        tree: Tree,
        key: IVec,
        value: Option<IVec>,
    ) -> Event {
        Event::single_batch(
            tree,
            Batch { writes: vec![(key, value)].into_iter().collect() },
        )
    }

    pub(crate) fn single_batch(tree: Tree, batch: Batch) -> Event {
        Event::from_batches(vec![(tree, batch)])
    }

    pub(crate) fn from_batches(batches: Vec<(Tree, Batch)>) -> Event {
        Event { batches: Arc::from(batches.into_boxed_slice()) }
    }

    /// Iterate over each Tree, key, and optional value in this `Event`
    pub fn iter<'a>(
        &'a self,
    ) -> Box<dyn 'a + Iterator<Item = (&'a Tree, &'a IVec, &'a Option<IVec>)>>
    {
        self.into_iter()
    }
}

impl<'a> IntoIterator for &'a Event {
    type Item = (&'a Tree, &'a IVec, &'a Option<IVec>);
    type IntoIter = Box<dyn 'a + Iterator<Item = Self::Item>>;

    fn into_iter(self) -> Self::IntoIter {
        Box::new(self.batches.iter().flat_map(|(ref tree, ref batch)| {
            batch.writes.iter().map(move |(k, v_opt)| (tree, k, v_opt))
        }))
    }
}

type Senders = Map<usize, (Option<Waker>, SyncSender<OneShot<Option<Event>>>)>;

/// A subscriber listening on a specified prefix
///
/// `Subscriber` implements both `Iterator<Item = Event>`
/// and `Future<Output=Option<Event>>`
///
/// # Examples
///
/// Synchronous, blocking subscriber:
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use sled::{Config, Event};
/// let config = Config::new().temporary(true);
///
/// let tree = config.open()?;
///
/// // watch all events by subscribing to the empty prefix
/// let mut subscriber = tree.watch_prefix(vec![]);
///
/// let tree_2 = tree.clone();
/// let thread = std::thread::spawn(move || {
///     tree.insert(vec![0], vec![1])
/// });
///
/// // `Subscription` implements `Iterator<Item=Event>`
/// for event in subscriber.take(1) {
///     // Events occur due to single key operations,
///     // batches, or transactions. The tree is included
///     // so that you may perform a new transaction or
///     // operation in response to the event.
///     for (tree, key, value_opt) in &event {
///         if let Some(value) = value_opt {
///             // key `key` was set to value `value`
///         } else {
///             // key `key` was removed
///         }
///     }
/// }
///
/// # thread.join().unwrap();
/// # Ok(())
/// # }
/// ```
/// Aynchronous, non-blocking subscriber:
///
/// `Subscription` implements `Future<Output=Option<Event>>`.
///
/// `while let Some(event) = (&mut subscriber).await { /* use it */ }`
pub struct Subscriber {
    id: usize,
    rx: Receiver<OneShot<Option<Event>>>,
    home: Arc<RwLock<Senders>>,
}

impl Drop for Subscriber {
    fn drop(&mut self) {
        let mut w_senders = self.home.write();
        w_senders.remove(&self.id);
    }
}

impl Subscriber {
    /// Attempts to wait for a value on this `Subscriber`, returning
    /// an error if no event arrives within the provided `Duration`
    /// or if the backing `Db` shuts down.
    pub fn next_timeout(
        &self,
        mut timeout: Duration,
    ) -> std::result::Result<Event, std::sync::mpsc::RecvTimeoutError> {
        loop {
            let start = Instant::now();
            let future_rx = self.rx.recv_timeout(timeout)?;
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };

            let start = Instant::now();
            if let Some(event) = future_rx.wait_timeout(timeout)? {
                return Ok(event);
            }
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };
        }
    }
}

impl Future for Subscriber {
    type Output = Option<Event>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.rx.try_recv() {
                Ok(mut future_rx) => {
                    #[allow(unsafe_code)]
                    let future_rx =
                        unsafe { std::pin::Pin::new_unchecked(&mut future_rx) };

                    match Future::poll(future_rx, cx) {
                        Poll::Ready(Some(event)) => {
                            return Poll::Ready(event);
                        }
                        Poll::Ready(None) => {
                            continue;
                        }
                        Poll::Pending => {
                            return Poll::Pending;
                        }
                    }
                }
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => return Poll::Ready(None),
            }
        }
        let mut home = self.home.write();
        let entry = home.get_mut(&self.id).unwrap();
        entry.0 = Some(cx.waker().clone());
        Poll::Pending
    }
}

impl Iterator for Subscriber {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        loop {
            let future_rx = self.rx.recv().ok()?;
            match future_rx.wait() {
                Some(Some(event)) => return Some(event),
                Some(None) => return None,
                None => continue,
            }
        }
    }
}

#[derive(Debug, Default)]
pub(crate) struct Subscribers {
    watched: RwLock<BTreeMap<Vec<u8>, Arc<RwLock<Senders>>>>,
    ever_used: AtomicBool,
}

impl Drop for Subscribers {
    fn drop(&mut self) {
        let watched = self.watched.read();

        for senders in watched.values() {
            let senders =
                std::mem::replace(&mut *senders.write(), Map::default());
            for (_, (waker, sender)) in senders {
                drop(sender);
                if let Some(waker) = waker {
                    waker.wake();
                }
            }
        }
    }
}

impl Subscribers {
    pub(crate) fn register(&self, prefix: &[u8]) -> Subscriber {
        self.ever_used.store(true, Relaxed);
        let r_mu = {
            let r_mu = self.watched.read();
            if r_mu.contains_key(prefix) {
                r_mu
            } else {
                drop(r_mu);
                let mut w_mu = self.watched.write();
                if !w_mu.contains_key(prefix) {
                    let old = w_mu.insert(
                        prefix.to_vec(),
                        Arc::new(RwLock::new(Map::default())),
                    );
                    assert!(old.is_none());
                }
                drop(w_mu);
                self.watched.read()
            }
        };

        let (tx, rx) = sync_channel(1024);

        let arc_senders = &r_mu[prefix];
        let mut w_senders = arc_senders.write();

        let id = ID_GEN.fetch_add(1, Relaxed);

        w_senders.insert(id, (None, tx));

        Subscriber { id, rx, home: arc_senders.clone() }
    }

    pub(crate) fn reserve_batch(
        &self,
        batch: &Batch,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();

        let mut skip_indices = std::collections::HashSet::new();
        let mut subscribers = vec![];

        for key in batch.writes.keys() {
            for (idx, (prefix, subs_rwl)) in r_mu.iter().enumerate() {
                if key.starts_with(prefix) && !skip_indices.contains(&idx) {
                    skip_indices.insert(idx);
                    let subs = subs_rwl.read();

                    for (_id, (waker, sender)) in subs.iter() {
                        let (tx, rx) = OneShot::pair();
                        if sender.send(rx).is_err() {
                            continue;
                        }
                        subscribers.push((waker.clone(), tx));
                    }
                }
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }

    pub(crate) fn reserve<R: AsRef<[u8]>>(
        &self,
        key: R,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();
        let prefixes = r_mu.iter().filter(|(k, _)| key.as_ref().starts_with(k));

        let mut subscribers = vec![];

        for (_, subs_rwl) in prefixes {
            let subs = subs_rwl.read();

            for (_id, (waker, sender)) in subs.iter() {
                let (tx, rx) = OneShot::pair();
                if sender.send(rx).is_err() {
                    continue;
                }
                subscribers.push((waker.clone(), tx));
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }
}

pub(crate) struct ReservedBroadcast {
    subscribers: Vec<(Option<Waker>, OneShotFiller<Option<Event>>)>,
}

impl ReservedBroadcast {
    pub fn complete(self, event: &Event) {
        let iter = self.subscribers.into_iter();

        for (waker, tx) in iter {
            tx.fill(Some(event.clone()));
            if let Some(waker) = waker {
                waker.wake();
            }
        }
    }
}
<|endoftext|>


<commit_before>use bot::BotEnv;
use listeners::{Timeouts, PollTagger, AutoReplyListener, ReactionAuthorize};
use commands::*;

use lalafell::listeners::CommandListener;

use serenity::prelude::RwLock;
use serenity::client::{EventHandler, Context};
use serenity::model::id::GuildId;
use serenity::model::event::MessageUpdateEvent;
use serenity::model::channel::{Message, GuildChannel, Reaction};
use serenity::model::guild::Member;
use serenity::model::gateway::Ready;

use std::sync::Arc;

pub struct Handler {
  env: Arc<BotEnv>,
  listeners: Vec<Box<EventHandler + Send + Sync>>
}

impl Handler {
  pub fn new(env: Arc<BotEnv>) -> Self {
    let listeners: Vec<Box<EventHandler + Send + Sync>> = vec![
      box command_listener(&env),
      box ReactionAuthorize,
      box Timeouts,
      box PollTagger,
      box AutoReplyListener::default()
    ];
    Handler {
      env,
      listeners
    }
  }
}

impl EventHandler for Handler {
  fn message(&self, ctx: Context, msg: Message) {
    for listener in &self.listeners {
      listener.message(ctx.clone(), msg.clone());
    }
  }

  fn message_update(&self, ctx: Context, update: MessageUpdateEvent) {
    for listener in &self.listeners {
      listener.message_update(ctx.clone(), update.clone());
    }
  }

  fn guild_member_addition(&self, ctx: Context, guild: GuildId, member: Member) {
    for listener in &self.listeners {
      listener.guild_member_addition(ctx.clone(), guild, member.clone());
    }
  }

  fn reaction_add(&self, ctx: Context, reaction: Reaction) {
    for listener in &self.listeners {
      listener.reaction_add(ctx.clone(), reaction.clone());
    }
  }

  fn reaction_remove(&self, ctx: Context, reaction: Reaction) {
    for listener in &self.listeners {
      listener.reaction_remove(ctx.clone(), reaction.clone());
    }
  }

  fn channel_create(&self, ctx: Context, channel: Arc<RwLock<GuildChannel>>) {
    for listener in &self.listeners {
      listener.channel_create(ctx.clone(), Arc::clone(&channel));
    }
  }

  fn ready(&self, ctx: Context, _: Ready) {
    if let Some(g) = ::tasks::random_presence::random_game(self.env.as_ref()) {
      ctx.shard.set_game(Some(g));
    }
  }
}

macro_rules! command_listener {
  (env => $env:expr, $($($alias:expr),+ => $name:ident),+) => {{
    let mut command_listener = CommandListener::default();
    $(
      command_listener.add_command(&[$($alias),*], box $name::new(Arc::clone(&$env)));
    )*
    command_listener
  }}
}

fn command_listener<'a>(env: &Arc<BotEnv>) -> CommandListener<'a> {
  command_listener! {
    env => env,
    "race" => RaceCommand,
    "tag" => TagCommand,
    "autotag" => AutoTagCommand,
    "viewtag" => ViewTagCommand,
    "updatetags" => UpdateTagsCommand,
    "updatetag" => UpdateTagCommand,
    "verify" => VerifyCommand,
    "referencecount" => ReferenceCountCommand,
    "poll" => PollCommand,
    "pollresults" => PollResultsCommand,
    "timeout" => TimeoutCommand,
    "untimeout" => UntimeoutCommand,
    // "archive" => ArchiveCommand,
    "imagedump", "dump" => ImageDumpCommand,
    "configure", "config" => ConfigureCommand,
    "randomreaction", "reaction" => RandomReactionCommand,
    "search" => SearchCommand,
    "presence" => PresenceCommand,
    "ping" => PingCommand,
    "reload", "reloadconfig" => ReloadConfigCommand,
    "blob" => BlobCommand
  }
}
<commit_msg>refactor: move listener order<commit_after>use bot::BotEnv;
use listeners::{Timeouts, PollTagger, AutoReplyListener, ReactionAuthorize};
use commands::*;

use lalafell::listeners::CommandListener;

use serenity::prelude::RwLock;
use serenity::client::{EventHandler, Context};
use serenity::model::id::GuildId;
use serenity::model::event::MessageUpdateEvent;
use serenity::model::channel::{Message, GuildChannel, Reaction};
use serenity::model::guild::Member;
use serenity::model::gateway::Ready;

use std::sync::Arc;

pub struct Handler {
  env: Arc<BotEnv>,
  listeners: Vec<Box<EventHandler + Send + Sync>>
}

impl Handler {
  pub fn new(env: Arc<BotEnv>) -> Self {
    let listeners: Vec<Box<EventHandler + Send + Sync>> = vec![
      box ReactionAuthorize,
      box Timeouts,
      box PollTagger,
      box AutoReplyListener::default(),
      box command_listener(&env)
    ];
    Handler {
      env,
      listeners
    }
  }
}

impl EventHandler for Handler {
  fn message(&self, ctx: Context, msg: Message) {
    for listener in &self.listeners {
      listener.message(ctx.clone(), msg.clone());
    }
  }

  fn message_update(&self, ctx: Context, update: MessageUpdateEvent) {
    for listener in &self.listeners {
      listener.message_update(ctx.clone(), update.clone());
    }
  }

  fn guild_member_addition(&self, ctx: Context, guild: GuildId, member: Member) {
    for listener in &self.listeners {
      listener.guild_member_addition(ctx.clone(), guild, member.clone());
    }
  }

  fn reaction_add(&self, ctx: Context, reaction: Reaction) {
    for listener in &self.listeners {
      listener.reaction_add(ctx.clone(), reaction.clone());
    }
  }

  fn reaction_remove(&self, ctx: Context, reaction: Reaction) {
    for listener in &self.listeners {
      listener.reaction_remove(ctx.clone(), reaction.clone());
    }
  }

  fn channel_create(&self, ctx: Context, channel: Arc<RwLock<GuildChannel>>) {
    for listener in &self.listeners {
      listener.channel_create(ctx.clone(), Arc::clone(&channel));
    }
  }

  fn ready(&self, ctx: Context, _: Ready) {
    if let Some(g) = ::tasks::random_presence::random_game(self.env.as_ref()) {
      ctx.shard.set_game(Some(g));
    }
  }
}

macro_rules! command_listener {
  (env => $env:expr, $($($alias:expr),+ => $name:ident),+) => {{
    let mut command_listener = CommandListener::default();
    $(
      command_listener.add_command(&[$($alias),*], box $name::new(Arc::clone(&$env)));
    )*
    command_listener
  }}
}

fn command_listener<'a>(env: &Arc<BotEnv>) -> CommandListener<'a> {
  command_listener! {
    env => env,
    "race" => RaceCommand,
    "tag" => TagCommand,
    "autotag" => AutoTagCommand,
    "viewtag" => ViewTagCommand,
    "updatetags" => UpdateTagsCommand,
    "updatetag" => UpdateTagCommand,
    "verify" => VerifyCommand,
    "referencecount" => ReferenceCountCommand,
    "poll" => PollCommand,
    "pollresults" => PollResultsCommand,
    "timeout" => TimeoutCommand,
    "untimeout" => UntimeoutCommand,
    // "archive" => ArchiveCommand,
    "imagedump", "dump" => ImageDumpCommand,
    "configure", "config" => ConfigureCommand,
    "randomreaction", "reaction" => RandomReactionCommand,
    "search" => SearchCommand,
    "presence" => PresenceCommand,
    "ping" => PingCommand,
    "reload", "reloadconfig" => ReloadConfigCommand,
    "blob" => BlobCommand
  }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
use serialize::json;
use std::str::from_utf8;

use curl::http;
use structs::{Node, Service};

#[deriving(Decodable, Encodable, Show)]
pub struct HealthService{
    Node: Node,
    Service: Service,
}

pub struct Health{
    address: String,
}

impl Health {

    pub fn new(address: &str) -> Health {
        Health{address: address.to_string()}
    }

    fn request(&self, url: &str) -> Vec<HealthService> {
        let resp = http::handle().get(url).exec().unwrap();
        let result = from_utf8(resp.get_body()).unwrap();
        json::decode(result).unwrap()
    }

   // Rust does not support default parameters or optional parameters for now, so `tags` must be provided
   pub fn service(&self, name: &str, tags: &str) -> Vec<HealthService>{
       let url =
             if tags == "" {
                self.address + "/health/service/" + name
             } else {
                self.address + "/health/service/" + name + "?tag=" + tags
             };

        self.request(url.as_slice())
   }
}
<commit_msg>change struct field permission<commit_after>#![allow(non_snake_case)]
use serialize::json;
use std::str::from_utf8;

use curl::http;
use structs::{Node, Service};

#[deriving(Decodable, Encodable, Show)]
pub struct HealthService{
    pub Node: Node,
    pub Service: Service,
}

pub struct Health{
    address: String,
}

impl Health {

    pub fn new(address: &str) -> Health {
        Health{address: address.to_string()}
    }

    fn request(&self, url: &str) -> Vec<HealthService> {
        let resp = http::handle().get(url).exec().unwrap();
        let result = from_utf8(resp.get_body()).unwrap();
        json::decode(result).unwrap()
    }

   // Rust does not support default parameters or optional parameters for now, so `tags` must be provided
   pub fn service(&self, name: &str, tags: &str) -> Vec<HealthService>{
       let url =
             if tags == "" {
                self.address + "/health/service/" + name
             } else {
                self.address + "/health/service/" + name + "?tag=" + tags
             };

        self.request(url.as_slice())
   }
}
<|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
use geo;
use geo::contains::Contains;
use gst::rtree::{RTree, Rect};
use mimir::Admin;
use std;
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
use std::sync::Arc;

/// We want to strip the admin's boundary for the objects referencing it (for performance purpose)
/// thus in the `AdminGeoFinder` we store an Admin without the boundary (the option is emptied)
/// and we store the boundary aside
struct BoundaryAndAdmin(Option<geo::MultiPolygon<f64>>, Arc<Admin>);

impl BoundaryAndAdmin {
    fn new(mut admin: Admin) -> BoundaryAndAdmin {
        let b = std::mem::replace(&mut admin.boundary, None);
        let minimal_admin = Arc::new(admin);
        BoundaryAndAdmin(b, minimal_admin)
    }
}

pub struct AdminGeoFinder {
    admins: RTree<BoundaryAndAdmin>,
    parents_map: BTreeMap<String, String>,
}

impl AdminGeoFinder {
    pub fn insert(&mut self, admin: Admin) {
        use ordered_float::OrderedFloat;
        fn min(a: OrderedFloat<f32>, b: f64) -> f32 {
            a.0.min(down(b as f32))
        }
        fn max(a: OrderedFloat<f32>, b: f64) -> f32 {
            a.0.max(up(b as f32))
        }

        let rect = {
            let mut coords = match admin.boundary {
                Some(ref b) => (*b).0.iter().flat_map(|poly| (poly.exterior).0.iter()),
                None => return,
            };
            let first_coord = match coords.next() {
                Some(c) => c,
                None => return,
            };
            let first_rect: Rect = {
                let (x, y) = (first_coord.x() as f32, first_coord.y() as f32);
                Rect::from_float(down(x), up(x), down(y), up(y))
            };
            coords.fold(first_rect, |accu, p| {
                Rect::from_float(
                    min(accu.xmin, p.x()),
                    max(accu.xmax, p.x()),
                    min(accu.ymin, p.y()),
                    max(accu.ymax, p.y()),
                )
            })
        };
        if let Some(parent_id) = &admin.parent_id {
            self.parents_map.insert(admin.id.clone(), parent_id.clone());
        }
        self.admins.insert(rect, BoundaryAndAdmin::new(admin));
    }

    /// Get all Admins overlapping the coordinate
    pub fn get(&self, coord: &geo::Coordinate<f64>) -> Vec<Arc<Admin>> {
        let (x, y) = (coord.x as f32, coord.y as f32);
        let search = Rect::from_float(down(x), up(x), down(y), up(y));
        let mut rtree_results = self.admins.get(&search);

        rtree_results.sort_by_key(|(_, a)| (*a.1).zone_type);

        let mut tested_hierarchy = BTreeSet::<String>::new();
        let mut res = vec![];

        for boundary_and_admin in rtree_results.into_iter().map(|(_, a)| a) {
            let boundary = &boundary_and_admin.0;
            let admin = &boundary_and_admin.1;
            if tested_hierarchy.contains(&(*admin).id)
                || boundary
                    .as_ref()
                    .map_or(false, |b| (*b).contains(&geo::Point(*coord)))
            {
                let mut admin_parent = (*admin).parent_id.clone();
                while let Some(id) = admin_parent {
                    admin_parent = self.parents_map.get(&id).cloned();
                    tested_hierarchy.insert(id);
                }

                res.push(admin.clone());
            }
        }
        res
    }

    /// Iterates on all the admins with a not None boundary.
    pub fn admins<'a>(&'a self) -> Box<Iterator<Item = Admin> + 'a> {
        let iter = self
            .admins
            .get(&Rect::from_float(
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
            ))
            .into_iter()
            .map(|(_, a)| {
                let mut admin = (*a.1).clone();
                admin.boundary = a.0.clone();
                admin
            });
        Box::new(iter)
    }

    /// Iterates on all the `Rc<Admin>` in the structure as returned by `get`.
    pub fn admins_without_boundary<'a>(&'a self) -> Box<Iterator<Item = Arc<Admin>> + 'a> {
        let iter = self
            .admins
            .get(&Rect::from_float(
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
            ))
            .into_iter()
            .map(|(_, a)| a.1.clone());
        Box::new(iter)
    }
}

impl Default for AdminGeoFinder {
    fn default() -> Self {
        AdminGeoFinder {
            admins: RTree::new(),
            parents_map: BTreeMap::new(),
        }
    }
}

impl FromIterator<Admin> for AdminGeoFinder {
    fn from_iter<I: IntoIterator<Item = Admin>>(admins: I) -> Self {
        let mut geofinder = AdminGeoFinder::default();

        for admin in admins {
            geofinder.insert(admin);
        }

        geofinder
    }
}

// the goal is that f in [down(f as f32) as f64, up(f as f32) as f64]
fn down(f: f32) -> f32 {
    f - (f * ::std::f32::EPSILON).abs()
}
fn up(f: f32) -> f32 {
    f + (f * ::std::f32::EPSILON).abs()
}

#[test]
fn test_up_down() {
    for &f in [1.0f64, 0., -0., -1., 0.1, -0.1, 0.9, -0.9, 42., -42.].iter() {
        let small_f = f as f32;
        assert!(
            down(small_f) as f64 <= f,
            format!("{} <= {}", down(small_f) as f64, f)
        );
        assert!(
            f <= up(small_f) as f64,
            format!("{} <= {}", f, up(small_f) as f64)
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cosmogony::ZoneType;
    use geo::prelude::BoundingBox;
    use mimir::AdminType;

    fn p(x: f64, y: f64) -> ::geo::Point<f64> {
        ::geo::Point(::geo::Coordinate { x: x, y: y })
    }

    fn make_admin(offset: f64) -> ::mimir::Admin {
        // the boundary is a big octogon
        let shape = ::geo::Polygon::new(
            ::geo::LineString(vec![
                p(3. + offset, 0. + offset),
                p(6. + offset, 0. + offset),
                p(9. + offset, 3. + offset),
                p(9. + offset, 6. + offset),
                p(6. + offset, 9. + offset),
                p(3. + offset, 9. + offset),
                p(0. + offset, 6. + offset),
                p(0. + offset, 3. + offset),
                p(3. + offset, 0. + offset),
            ]),
            vec![],
        );
        let boundary = ::geo::MultiPolygon(vec![shape]);

        ::mimir::Admin {
            id: format!("admin:offset:{}", offset),
            level: 8,
            name: "city".to_string(),
            label: format!("city {}", offset),
            zip_codes: vec!["421337".to_string()],
            weight: 0f64,
            coord: ::mimir::Coord::new(4.0 + offset, 4.0 + offset),
            bbox: boundary.bbox(),
            boundary: Some(boundary),
            insee: "outlook".to_string(),
            admin_type: AdminType::City,
            zone_type: Some(ZoneType::City),
            parent_id: None,
        }
    }

    #[test]
    fn test_two_fake_admins() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40.));
        finder.insert(make_admin(43.));

        // outside
        for coord in [p(48., 41.), p(411., 41.), p(51., 54.), p(53., 53.)].iter() {
            assert!(finder.get(&coord.0).is_empty());
        }

        // inside one
        let admins = finder.get(&p(44., 44.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:40");
        let admins = finder.get(&p(48., 48.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:43");

        // inside two
        let mut admins = finder.get(&p(46., 46.).0);
        admins.sort_by(|a, b| a.id.cmp(&b.id));
        assert_eq!(admins.len(), 2);
        assert_eq!(admins[0].id, "admin:offset:40");
        assert_eq!(admins[1].id, "admin:offset:43");
    }
}
<commit_msg>Filter by types<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
use geo;
use geo::contains::Contains;
use gst::rtree::{RTree, Rect};
use mimir::Admin;
use std;
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
use std::sync::Arc;

/// We want to strip the admin's boundary for the objects referencing it (for performance purpose)
/// thus in the `AdminGeoFinder` we store an Admin without the boundary (the option is emptied)
/// and we store the boundary aside
struct BoundaryAndAdmin(Option<geo::MultiPolygon<f64>>, Arc<Admin>);

impl BoundaryAndAdmin {
    fn new(mut admin: Admin) -> BoundaryAndAdmin {
        let b = std::mem::replace(&mut admin.boundary, None);
        let minimal_admin = Arc::new(admin);
        BoundaryAndAdmin(b, minimal_admin)
    }
}

pub struct AdminGeoFinder {
    admins: RTree<BoundaryAndAdmin>,
    admin_by_id: BTreeMap<String, Arc<Admin>>,
}

impl AdminGeoFinder {
    pub fn insert(&mut self, admin: Admin) {
        use ordered_float::OrderedFloat;
        fn min(a: OrderedFloat<f32>, b: f64) -> f32 {
            a.0.min(down(b as f32))
        }
        fn max(a: OrderedFloat<f32>, b: f64) -> f32 {
            a.0.max(up(b as f32))
        }

        let rect = {
            let mut coords = match admin.boundary {
                Some(ref b) => (*b).0.iter().flat_map(|poly| (poly.exterior).0.iter()),
                None => return,
            };
            let first_coord = match coords.next() {
                Some(c) => c,
                None => return,
            };
            let first_rect: Rect = {
                let (x, y) = (first_coord.x() as f32, first_coord.y() as f32);
                Rect::from_float(down(x), up(x), down(y), up(y))
            };
            coords.fold(first_rect, |accu, p| {
                Rect::from_float(
                    min(accu.xmin, p.x()),
                    max(accu.xmax, p.x()),
                    min(accu.ymin, p.y()),
                    max(accu.ymax, p.y()),
                )
            })
        };
        let bound_admin = BoundaryAndAdmin::new(admin);
        self.admin_by_id
            .insert((*bound_admin.1).id.clone(), bound_admin.1.clone());
        self.admins.insert(rect, bound_admin);
    }

    /// Get all Admins overlapping the coordinate
    pub fn get(&self, coord: &geo::Coordinate<f64>) -> Vec<Arc<Admin>> {
        let (x, y) = (coord.x as f32, coord.y as f32);
        let search = Rect::from_float(down(x), up(x), down(y), up(y));
        let mut rtree_results = self.admins.get(&search);

        rtree_results.sort_by_key(|(_, a)| (*a.1).zone_type);

        let mut tested_hierarchy = BTreeSet::<String>::new();
        let mut added_zone_types = BTreeSet::new();
        let mut res = vec![];

        for boundary_and_admin in rtree_results.into_iter().map(|(_, a)| a) {
            let boundary = &boundary_and_admin.0;
            let admin = &boundary_and_admin.1;
            if tested_hierarchy.contains(&(*admin).id) {
                res.push(admin.clone());
            } else if (*admin)
                .zone_type
                .as_ref()
                .map_or(false, |zt| added_zone_types.contains(zt))
            {
                // we don't want it, we already have this kind of ZoneType
            } else if boundary
                .as_ref()
                .map_or(false, |b| (*b).contains(&geo::Point(*coord)))
            {
                // we found a valid admin, we save it's hierarchy not to have to test their boundaries
                if let Some(zt) = (*admin).zone_type {
                    added_zone_types.insert(zt.clone());
                }
                let mut admin_parent_id = (*admin).parent_id.clone();
                while let Some(id) = admin_parent_id {
                    let admin_parent = self.admin_by_id.get(&id);
                    if let Some(zt) = admin_parent.as_ref().and_then(|a| (*a).zone_type) {
                        added_zone_types.insert(zt.clone());
                    }
                    tested_hierarchy.insert(id);
                    admin_parent_id = admin_parent.and_then(|a| (*a).parent_id.clone());
                }

                res.push(admin.clone());
            }
        }
        res
    }

    /// Iterates on all the admins with a not None boundary.
    pub fn admins<'a>(&'a self) -> Box<Iterator<Item = Admin> + 'a> {
        let iter = self
            .admins
            .get(&Rect::from_float(
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
            ))
            .into_iter()
            .map(|(_, a)| {
                let mut admin = (*a.1).clone();
                admin.boundary = a.0.clone();
                admin
            });
        Box::new(iter)
    }

    /// Iterates on all the `Rc<Admin>` in the structure as returned by `get`.
    pub fn admins_without_boundary<'a>(&'a self) -> Box<Iterator<Item = Arc<Admin>> + 'a> {
        let iter = self
            .admins
            .get(&Rect::from_float(
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
                std::f32::NEG_INFINITY,
                std::f32::INFINITY,
            ))
            .into_iter()
            .map(|(_, a)| a.1.clone());
        Box::new(iter)
    }
}

impl Default for AdminGeoFinder {
    fn default() -> Self {
        AdminGeoFinder {
            admins: RTree::new(),
            admin_by_id: BTreeMap::new(),
        }
    }
}

impl FromIterator<Admin> for AdminGeoFinder {
    fn from_iter<I: IntoIterator<Item = Admin>>(admins: I) -> Self {
        let mut geofinder = AdminGeoFinder::default();

        for admin in admins {
            geofinder.insert(admin);
        }

        geofinder
    }
}

// the goal is that f in [down(f as f32) as f64, up(f as f32) as f64]
fn down(f: f32) -> f32 {
    f - (f * ::std::f32::EPSILON).abs()
}
fn up(f: f32) -> f32 {
    f + (f * ::std::f32::EPSILON).abs()
}

#[test]
fn test_up_down() {
    for &f in [1.0f64, 0., -0., -1., 0.1, -0.1, 0.9, -0.9, 42., -42.].iter() {
        let small_f = f as f32;
        assert!(
            down(small_f) as f64 <= f,
            format!("{} <= {}", down(small_f) as f64, f)
        );
        assert!(
            f <= up(small_f) as f64,
            format!("{} <= {}", f, up(small_f) as f64)
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cosmogony::ZoneType;
    use geo::prelude::BoundingBox;
    use mimir::AdminType;

    fn p(x: f64, y: f64) -> ::geo::Point<f64> {
        ::geo::Point(::geo::Coordinate { x: x, y: y })
    }

    fn make_admin(offset: f64, zt: Option<ZoneType>) -> ::mimir::Admin {
        make_complex_admin(&format!("admin:offset:{}", offset,), offset, zt, 1., None)
    }

    fn make_complex_admin(
        id: &str,
        offset: f64,
        zt: Option<ZoneType>,
        zone_size: f64,
        parent_offset: Option<&str>,
    ) -> ::mimir::Admin {
        // the boundary is a big octogon
        // the zone_size param is used to control the area of the zone
        let shape = ::geo::Polygon::new(
            ::geo::LineString(vec![
                p(3. * zone_size + offset, 0. * zone_size + offset),
                p(6. * zone_size + offset, 0. * zone_size + offset),
                p(9. * zone_size + offset, 3. * zone_size + offset),
                p(9. * zone_size + offset, 6. * zone_size + offset),
                p(6. * zone_size + offset, 9. * zone_size + offset),
                p(3. * zone_size + offset, 9. * zone_size + offset),
                p(0. * zone_size + offset, 6. * zone_size + offset),
                p(0. * zone_size + offset, 3. * zone_size + offset),
                p(3. * zone_size + offset, 0. * zone_size + offset),
            ]),
            vec![],
        );
        let boundary = ::geo::MultiPolygon(vec![shape]);

        ::mimir::Admin {
            id: id.into(),
            level: 8,
            name: "city".to_string(),
            label: format!("city {}", offset),
            zip_codes: vec!["421337".to_string()],
            weight: 0f64,
            coord: ::mimir::Coord::new(4.0 + offset, 4.0 + offset),
            bbox: boundary.bbox(),
            boundary: Some(boundary),
            insee: "outlook".to_string(),
            admin_type: AdminType::City,
            zone_type: zt,
            parent_id: parent_offset.map(|id| id.into()),
        }
    }

    #[test]
    fn test_two_fake_admins() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., Some(ZoneType::City)));
        finder.insert(make_admin(43., Some(ZoneType::State)));

        // outside
        for coord in [p(48., 41.), p(411., 41.), p(51., 54.), p(53., 53.)].iter() {
            assert!(finder.get(&coord.0).is_empty());
        }

        // inside one
        let admins = finder.get(&p(44., 44.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:40");
        let admins = finder.get(&p(48., 48.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:43");

        // inside two
        let mut admins = finder.get(&p(46., 46.).0);
        admins.sort_by(|a, b| a.id.cmp(&b.id));
        assert_eq!(admins.len(), 2);
        assert_eq!(admins[0].id, "admin:offset:40");
        assert_eq!(admins[1].id, "admin:offset:43");
    }

    #[test]
    fn test_two_admin_same_zone_type() {
        // a point can be associated to only 1 admin type
        // so a point is in 2 city, it is associated to only one
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., Some(ZoneType::City)));
        finder.insert(make_admin(43., Some(ZoneType::City)));
        let mut admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 1);
    }

    #[test]
    fn test_two_no_zone_type() {
        // a point can be associated to only 1 admin type
        // but a point can be associated to multiple admin without zone_type
        // (for retrocompatibility of the data imported without cosmogony)
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., None));
        finder.insert(make_admin(43., None));
        let mut admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 2);
    }

    #[test]
    fn test_hierarchy() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        let mut admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 3);
        assert_eq!(admins[0].id, "bob_city");
        assert_eq!(admins[1].id, "bob_state");
        assert_eq!(admins[2].id, "bob_country");
    }

    #[test]
    fn test_hierarchy_orphan() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        // another_state also contains the point, but the geofinder look for only 1 admin by type (it needs only 1 state)
        // since bob_city has been tester first, it's hierarchy has been added automatically
        // so [46., 46.] will not be associated to another_state
        finder.insert(make_complex_admin(
            "another_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));

        let mut admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 3);
        assert_eq!(admins[0].id, "bob_city");
        assert_eq!(admins[1].id, "bob_state");
        assert_eq!(admins[2].id, "bob_country");
    }

    #[test]
    fn test_hierarchy_and_not_typed_zone() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        // not_typed zone is outside the hierarchy, but since it contains the point and it has no type it is added
        finder.insert(make_complex_admin("no_typed_zone", 40., None, 2., None));

        let mut admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 4);
        assert_eq!(admins[0].id, "no_typed_zone");
        assert_eq!(admins[1].id, "bob_city");
        assert_eq!(admins[2].id, "bob_state");
        assert_eq!(admins[3].id, "bob_country");
    }
}
<|endoftext|>


<commit_before>use glium::backend::Facade;
use glium::{self, BackfaceCullingMode, DepthTest, DrawParameters, IndexBuffer, VertexBuffer};
use glium::index::PrimitiveType;
use Camera;
use util::ToArr;
use base::math::*;
use base::gen::seeded_rng;
use base::prop::plant::{Plant, Tree};
use std::rc::Rc;
use super::PlantRenderer;
use base::prop::plant::ControlPoint;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    vertices: VertexBuffer<Vertex>,
    indices: IndexBuffer<u32>,
    renderer: Rc<PlantRenderer>,
    pos: Point3f,
}

impl PlantView {
    pub fn from_plant<F: Facade>(pos: Point3f,
                                 plant: &Plant,
                                 renderer: Rc<PlantRenderer>,
                                 facade: &F)
                                 -> Self {
        let mut indices = Vec::new();
        let mut vertices = Vec::new();
        match *plant {
            Plant::Tree(Tree { ref branches, trunk_color, leaf_color }) => {
                for branch in branches {
                    gen_branch_buffer(&branch.points, &mut vertices, &mut indices, branch_color);
                }
            }
        };

        PlantView {
            vertices: VertexBuffer::new(facade, &vertices).unwrap(),
            indices: IndexBuffer::new(facade,
                                      PrimitiveType::Patches { vertices_per_patch: 3 },
                                      &indices)
                .unwrap(),
            renderer: renderer,
            pos: pos,
        }
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.shadow_program(),
                  &uniforms,
                  &params)
            .unwrap();
    }

    pub fn draw<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let tess_level_inner = 10.0 as f32;
        let tess_level_outer = 10.0 as f32;

        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
            tess_level_inner: tess_level_inner,
            tess_level_outer: tess_level_outer,
            camera_pos: camera.position.to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullCounterClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.program(),
                  &uniforms,
                  &params)
            .unwrap();

    }
}

/// Vertex type used to render plants/trees.
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 3],
    pub normal: [f32; 3],
}

implement_vertex!(Vertex, position, color, normal);

/// generates VertexBuffer and IndexBuffer for Plants
fn gen_branch_buffer(old_cps: &[ControlPoint],
                     vertices: &mut Vec<Vertex>,
                     indices: &mut Vec<u32>,
                     color: Vector3f) {
    let old_index_offset = vertices.len() as u32;
    let cps = {
        let mut cps = vec![old_cps[0]];
        cps.extend_from_slice(old_cps);
        cps.push(*old_cps.last().unwrap());
        cps
    };

    for window in cps.windows(3) {
        let prev_cp = window[0];
        let curr_cp = window[1];
        let next_cp = window[2];

        let dir = prev_cp.point - next_cp.point;

        for curr_point in &get_points_from_vector(dir) {
            vertices.push(Vertex {
                position: (curr_cp.point + curr_point * curr_cp.diameter).to_arr(),
                color: color.to_arr(),
                normal: curr_point.to_arr(),
            });
        }
    }

    for offset in 0..(old_cps.len() as u32) - 1 {
        let offset = offset * 3;
        let segment_indices = [0, 1, 3, 4, 3, 1, 1, 2, 4, 5, 4, 2, 2, 0, 5, 3, 5, 0];

        indices.extend(segment_indices.into_iter().map(|i| i + offset + old_index_offset));
    }

    let vert_len = vertices.len() as u32;
    indices.extend_from_slice(&[vert_len - 3, vert_len - 2, vert_len - 1]);
}

/// generates 3 normalized vectors perpendicular to the given vector
fn get_points_from_vector(vector: Vector3f) -> [Vector3f; 3] {
    let ortho = random_vec_with_angle(&mut seeded_rng(0x2651aa465abded, (), ()), vector, 90.0);
    let rot = Basis3::from_axis_angle(vector.normalize(), Deg::new(120.0).into());
    let v0 = rot.rotate_vector(ortho);
    let v1 = rot.rotate_vector(v0);

    [ortho.normalize(), v0.normalize(), v1.normalize()]
}
<commit_msg>adding leaf and trunk color<commit_after>use glium::backend::Facade;
use glium::{self, BackfaceCullingMode, DepthTest, DrawParameters, IndexBuffer, VertexBuffer};
use glium::index::PrimitiveType;
use Camera;
use util::ToArr;
use base::math::*;
use base::gen::seeded_rng;
use base::prop::plant::{Plant, Tree};
use std::rc::Rc;
use super::PlantRenderer;
use base::prop::plant::ControlPoint;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    vertices: VertexBuffer<Vertex>,
    indices: IndexBuffer<u32>,
    renderer: Rc<PlantRenderer>,
    pos: Point3f,
}

impl PlantView {
    pub fn from_plant<F: Facade>(pos: Point3f,
                                 plant: &Plant,
                                 renderer: Rc<PlantRenderer>,
                                 facade: &F)
                                 -> Self {
        let mut indices = Vec::new();
        let mut vertices = Vec::new();
        match *plant {
            Plant::Tree(Tree { ref branches, trunk_color, leaf_color }) => {
                for branch in branches {
                    let color = if branch.is_trunk { trunk_color } else { leaf_color };
                    gen_branch_buffer(&branch.points, &mut vertices, &mut indices, color);
                }
            }
        };

        PlantView {
            vertices: VertexBuffer::new(facade, &vertices).unwrap(),
            indices: IndexBuffer::new(facade,
                                      PrimitiveType::Patches { vertices_per_patch: 3 },
                                      &indices)
                .unwrap(),
            renderer: renderer,
            pos: pos,
        }
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.shadow_program(),
                  &uniforms,
                  &params)
            .unwrap();
    }

    pub fn draw<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let tess_level_inner = 10.0 as f32;
        let tess_level_outer = 10.0 as f32;

        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
            tess_level_inner: tess_level_inner,
            tess_level_outer: tess_level_outer,
            camera_pos: camera.position.to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullCounterClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.program(),
                  &uniforms,
                  &params)
            .unwrap();

    }
}

/// Vertex type used to render plants/trees.
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 3],
    pub normal: [f32; 3],
}

implement_vertex!(Vertex, position, color, normal);

/// generates VertexBuffer and IndexBuffer for Plants
fn gen_branch_buffer(old_cps: &[ControlPoint],
                     vertices: &mut Vec<Vertex>,
                     indices: &mut Vec<u32>,
                     color: Vector3f) {
    let old_index_offset = vertices.len() as u32;
    let cps = {
        let mut cps = vec![old_cps[0]];
        cps.extend_from_slice(old_cps);
        cps.push(*old_cps.last().unwrap());
        cps
    };

    for window in cps.windows(3) {
        let prev_cp = window[0];
        let curr_cp = window[1];
        let next_cp = window[2];

        let dir = prev_cp.point - next_cp.point;

        for curr_point in &get_points_from_vector(dir) {
            vertices.push(Vertex {
                position: (curr_cp.point + curr_point * curr_cp.diameter).to_arr(),
                color: color.to_arr(),
                normal: curr_point.to_arr(),
            });
        }
    }

    for offset in 0..(old_cps.len() as u32) - 1 {
        let offset = offset * 3;
        let segment_indices = [0, 1, 3, 4, 3, 1, 1, 2, 4, 5, 4, 2, 2, 0, 5, 3, 5, 0];

        indices.extend(segment_indices.into_iter().map(|i| i + offset + old_index_offset));
    }

    let vert_len = vertices.len() as u32;
    indices.extend_from_slice(&[vert_len - 3, vert_len - 2, vert_len - 1]);
}

/// generates 3 normalized vectors perpendicular to the given vector
fn get_points_from_vector(vector: Vector3f) -> [Vector3f; 3] {
    let ortho = random_vec_with_angle(&mut seeded_rng(0x2651aa465abded, (), ()), vector, 90.0);
    let rot = Basis3::from_axis_angle(vector.normalize(), Deg::new(120.0).into());
    let v0 = rot.rotate_vector(ortho);
    let v1 = rot.rotate_vector(v0);

    [ortho.normalize(), v0.normalize(), v1.normalize()]
}
<|endoftext|>


<commit_before>extern crate reqwest;

use std::error::Error;
use std::result::Result;
use std::fmt;
use std::io;
use std::string;

use client::Endpoints;

// Result type that the client can return
pub type CDCResult<T> = Result<T, CDCError>;

#[derive(Debug)]
pub enum CDCError {
    // Generated by calling a method with an unsupported Endpoint
    // UnsupportedMethod(Endpoints, String),
    //
    // Generated by when a request tries to access an resource it is not authorized for
    NotAuthorized,

    // Generated by a failure to find a requested resource
    ResourceNotFound,

    // Generated by unknown server failures from the remote server
    APIFailure,

    // Generated by a bad request response from the server with a reason attached
    BadRequest(String),

    // Generated by a failure to parse an API response
    Convert(string::FromUtf8Error),

    // Generated by the networking client
    Network(reqwest::Error),

    // Generated by handling of network responses
    Io(io::Error),
}

impl fmt::Display for CDCError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CDCError::NotAuthorized => write!(f, "Not authorized to access this resource"),
            CDCError::ResourceNotFound => write!(f, "Specified resource could not be found"),
            CDCError::APIFailure => write!(f, "Unknown failure of the API endpoint"),
            CDCError::BadRequest(ref err_msg) => write!(f, "API did not understand request"),
            CDCError::Convert(ref err) => err.fmt(f),
            CDCError::Network(ref err) => err.fmt(f),
            CDCError::Io(ref err) => err.fmt(f),
        }
    }
}

impl Error for CDCError {
    fn description(&self) -> &str {
        match *self {
            CDCError::NotAuthorized => "",
            CDCError::ResourceNotFound => "",
            CDCError::APIFailure => "",
            CDCError::BadRequest(ref err_msg) => "",
            CDCError::Convert(ref err) => err.description(),
            CDCError::Network(ref err) => err.description(),
            CDCError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            CDCError::NotAuthorized => None,
            CDCError::ResourceNotFound => None,
            CDCError::APIFailure => None,
            CDCError::BadRequest(ref err_msg) => None,
            CDCError::Convert(ref err) => Some(err),
            CDCError::Network(ref err) => Some(err),
            CDCError::Io(ref err) => Some(err),
        }
    }
}

impl From<string::FromUtf8Error> for CDCError {
    fn from(err: string::FromUtf8Error) -> CDCError {
        CDCError::Convert(err)
    }
}

impl From<reqwest::Error> for CDCError {
    fn from(err: reqwest::Error) -> CDCError {
        CDCError::Network(err)
    }
}

impl From<io::Error> for CDCError {
    fn from(err: io::Error) -> CDCError {
        CDCError::Io(err)
    }
}
<commit_msg>Update error messages<commit_after>extern crate reqwest;

use std::error::Error;
use std::result::Result;
use std::fmt;
use std::io;
use std::string;

use client::Endpoints;

// Result type that the client can return
pub type CDCResult<T> = Result<T, CDCError>;

#[derive(Debug)]
pub enum CDCError {
    // Generated by calling a method with an unsupported Endpoint
    // UnsupportedMethod(Endpoints, String),
    //
    // Generated by when a request tries to access an resource it is not authorized for
    NotAuthorized,

    // Generated by a failure to find a requested resource
    ResourceNotFound,

    // Generated by unknown server failures from the remote server
    APIFailure,

    // Generated by a bad request response from the server with a reason attached
    BadRequest(String),

    // Generated by a failure to parse an API response
    Convert(string::FromUtf8Error),

    // Generated by the networking client
    Network(reqwest::Error),

    // Generated by handling of network responses
    Io(io::Error),
}

impl fmt::Display for CDCError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CDCError::NotAuthorized => {
                write!(f,
                       "Not authorized to access this resource. Ensure that valid key/secret pair \
                        with authorization to the resource have been supplied.")
            }
            CDCError::ResourceNotFound => write!(f, "Specified resource could not be found."),
            CDCError::APIFailure => write!(f, "Unknown failure of the API endpoint."),
            CDCError::BadRequest(ref err_msg) => {
                write!(f, "API did not understand request. {}", err_msg)
            }
            CDCError::Convert(ref err) => err.fmt(f),
            CDCError::Network(ref err) => err.fmt(f),
            CDCError::Io(ref err) => err.fmt(f),
        }
    }
}

impl Error for CDCError {
    fn description(&self) -> &str {
        match *self {
            CDCError::NotAuthorized => "Not authorized response from the API",
            CDCError::ResourceNotFound => "Specified resource could not be found",
            CDCError::APIFailure => "Unknown failure occured",
            CDCError::BadRequest(ref err_msg) => err_msg.as_str(),
            CDCError::Convert(ref err) => err.description(),
            CDCError::Network(ref err) => err.description(),
            CDCError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            CDCError::NotAuthorized => None,
            CDCError::ResourceNotFound => None,
            CDCError::APIFailure => None,
            CDCError::BadRequest(ref err_msg) => None,
            CDCError::Convert(ref err) => Some(err),
            CDCError::Network(ref err) => Some(err),
            CDCError::Io(ref err) => Some(err),
        }
    }
}

impl From<string::FromUtf8Error> for CDCError {
    fn from(err: string::FromUtf8Error) -> CDCError {
        CDCError::Convert(err)
    }
}

impl From<reqwest::Error> for CDCError {
    fn from(err: reqwest::Error) -> CDCError {
        CDCError::Network(err)
    }
}

impl From<io::Error> for CDCError {
    fn from(err: io::Error) -> CDCError {
        CDCError::Io(err)
    }
}
<|endoftext|>