<commit_before>//! asyncplify — Functional Reactive Programming (FRP) library (RX like) for rust.
//!
//! This library is the oposite of the iterator as those operators are pushed based instead of pull based like an iterator.
//! It can serve as a base for async operations and coordinations.
//!
//! # Example
//! ```
//! use asyncplify::*;
//!
//! let v = (0..10)
//!     .to_stream()     // convert the iterator to stream
//!     .map(|v| v + 10) // add 10 to all items coming from the stream
//!     .sum()           // sum all the values and push the sum to the stream
//!     .last_value()    // returns the last incoming values from the stream
//!     .unwrap();
//!
//! println!("The sum is {}", v);
//! ```
//!
//! Most operators are available under the [`Stream` trait](./trait.Stream.html).
//!
//! ## License
//! [The MIT License (MIT)](http://opensource.org/licenses/MIT)
//!

mod clonable;
mod consumer;
mod count;
mod dedup_by_key;
mod dedup;
mod empty;
mod filter;
mod flat_map;
mod fold;
mod group_by;
mod inspect;
mod interval;
mod into_vec;
mod iter;
mod last_value;
mod map;
mod max_by_key;
mod max;
mod min_by_key;
mod min;
mod once;
mod scan;
mod skip_last;
mod skip_until;
mod skip;
mod sort;
mod stream;
mod subscription;
mod sum;
mod take_last;
mod take_until;
mod take;
mod to_vec;
mod unique_by_key;
mod unique;
mod zip;

pub use clonable::*;
pub use consumer::*;
pub use count::*;
pub use dedup_by_key::*;
pub use dedup::*;
pub use empty::*;
pub use filter::*;
pub use flat_map::*;
pub use fold::*;
pub use group_by::*;
pub use inspect::*;
pub use interval::*;
pub use into_vec::*;
pub use iter::*;
pub use map::*;
pub use max_by_key::*;
pub use max::*;
pub use min_by_key::*;
pub use min::*;
pub use once::*;
pub use scan::*;
pub use skip_last::*;
pub use skip_until::*;
pub use skip::*;
pub use sort::*;
pub use stream::*;
pub use subscription::*;
pub use sum::*;
pub use take_last::*;
pub use take_until::*;
pub use take::*;
pub use to_vec::*;
pub use unique_by_key::*;
pub use unique::*;
pub use zip::*;

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

    #[test]
    fn it_works() {
        let mut f = 0i16;

        (0..100)
            .to_stream()
            .fold(0i16, |v, i| v + i)
            .subscribe_action(|v| f = v);
        assert!(f == 4950, "f = {}", f);
    }
}
<commit_msg>Hide subscription struct which are private<commit_after>//! asyncplify — Functional Reactive Programming (FRP) library (RX like) for rust.
//!
//! This library is the oposite of the iterator as those operators are pushed based instead of pull based like an iterator.
//! It can serve as a base for async operations and coordinations.
//!
//! # Example
//! ```
//! use asyncplify::*;
//!
//! let v = (0..10)
//!     .to_stream()     // convert the iterator to stream
//!     .map(|v| v + 10) // add 10 to all items coming from the stream
//!     .sum()           // sum all the values and push the sum to the stream
//!     .last_value()    // returns the last incoming values from the stream
//!     .unwrap();
//!
//! println!("The sum is {}", v);
//! ```
//!
//! Most operators are available under the [`Stream` trait](./trait.Stream.html).
//!
//! ## License
//! [The MIT License (MIT)](http://opensource.org/licenses/MIT)
//!

mod clonable;
mod consumer;
mod count;
mod dedup_by_key;
mod dedup;
mod empty;
mod filter;
mod flat_map;
mod fold;
mod group_by;
mod inspect;
mod interval;
mod into_vec;
mod iter;
mod last_value;
mod map;
mod max_by_key;
mod max;
mod min_by_key;
mod min;
mod once;
mod scan;
mod skip_last;
mod skip_until;
mod skip;
mod sort;
mod stream;
mod subscription;
mod sum;
mod take_last;
mod take_until;
mod take;
mod to_vec;
mod unique_by_key;
mod unique;
mod zip;

pub use clonable::*;
pub use consumer::*;
pub use count::*;
pub use dedup_by_key::*;
pub use dedup::*;
pub use empty::*;
pub use filter::*;
pub use flat_map::*;
pub use fold::*;
pub use group_by::*;
pub use inspect::*;
pub use interval::*;
pub use into_vec::*;
pub use iter::*;
pub use map::*;
pub use max_by_key::*;
pub use max::*;
pub use min_by_key::*;
pub use min::*;
pub use once::*;
pub use scan::*;
pub use skip_last::*;
pub use skip_until::*;
pub use skip::*;
pub use sort::*;
pub use stream::*;
pub use sum::*;
pub use take_last::*;
pub use take_until::*;
pub use take::*;
pub use to_vec::*;
pub use unique_by_key::*;
pub use unique::*;
pub use zip::*;

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

    #[test]
    fn it_works() {
        let mut f = 0i16;

        (0..100)
            .to_stream()
            .fold(0i16, |v, i| v + i)
            .subscribe_action(|v| f = v);
        assert!(f == 4950, "f = {}", f);
    }
}
<|endoftext|>


<commit_before>#![feature(io, core, std_misc, path, process)]
#![cfg_attr(test, deny(warnings))]

extern crate conduit;
extern crate flate2;

use std::ascii::AsciiExt;
use std::collections::hash_map::{HashMap, Entry};
use std::error::Error;
use std::io::prelude::*;
use std::io;
use std::path::PathBuf;
use std::process::{Command, Child, Stdio};

use conduit::{Request, Response};
use flate2::read::GzDecoder;

pub struct Serve(pub PathBuf);

impl Serve {
    fn doit(&self, req: &mut Request) -> io::Result<Response> {
        let mut cmd = Command::new("git");
        cmd.arg("http-backend");

        // Required environment variables
        cmd.env("REQUEST_METHOD",
                &format!("{:?}", req.method()).as_slice().to_ascii_uppercase());
        cmd.env("GIT_PROJECT_ROOT", &self.0);
        cmd.env("PATH_INFO", req.path());
        cmd.env("REMOTE_USER", "");
        cmd.env("REMOTE_ADDR", &req.remote_ip().to_string());
        cmd.env("QUERY_STRING", req.query_string().unwrap_or(""));
        cmd.env("CONTENT_TYPE", header(req, "Content-Type"));
        cmd.stderr(Stdio::inherit())
           .stdout(Stdio::capture())
           .stdin(Stdio::capture());
        let mut p = try!(cmd.spawn());

        // Pass in the body of the request (if any)
        //
        // As part of the CGI interface we're required to take care of gzip'd
        // requests. I'm not totally sure that this sequential copy is the best
        // thing to do or actually correct...
        if header(req, "Content-Encoding") == "gzip" {
            let mut body = try!(GzDecoder::new(req.body()));
            try!(io::copy(&mut body, &mut p.stdin.take().unwrap()));
        } else {
            try!(io::copy(&mut req.body(), &mut p.stdin.take().unwrap()));
        }

        // Parse the headers coming out, and the pass through the rest of the
        // process back down the stack.
        //
        // Note that we have to be careful to not drop the process which will wait
        // for the process to exit (and we haven't read stdout)
        let mut rdr = io::BufReader::new(p.stdout.take().unwrap());

        let mut headers = HashMap::new();
        for line in rdr.by_ref().lines() {
            let line = try!(line);
            if line.as_slice() == "\r" { break }

            let mut parts = line.as_slice().splitn(2, ':');
            let key = parts.next().unwrap();
            let value = parts.next().unwrap();
            let value = &value[1 .. value.len() - 1];
            match headers.entry(key.to_string()) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Vec::new()),
            }.push(value.to_string());
        }

        let (status_code, status_desc) = {
            let line = headers.remove("Status").unwrap_or(Vec::new());
            let line = line.into_iter().next().unwrap_or(String::new());
            let mut parts = line.as_slice().splitn(1, ' ');
            (parts.next().unwrap_or("").parse().unwrap_or(200),
             match parts.next() {
                 Some("Not Found") => "Not Found",
                 _ => "Ok",
             })
        };

        struct ProcessAndBuffer<R> { _p: Child, buf: io::BufReader<R> }
        impl<R: Read> Read for ProcessAndBuffer<R> {
            fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
                self.buf.read(b)
            }
        }
        return Ok(Response {
            status: (status_code, status_desc),
            headers: headers,
            body: Box::new(ProcessAndBuffer { _p: p, buf: rdr }),
        });

        fn header<'a>(req: &'a Request, name: &str) -> &'a str {
            let h = req.headers().find(name).unwrap_or(Vec::new());
            h.as_slice().get(0).map(|s| *s).unwrap_or("")
        }
    }
}

impl conduit::Handler for Serve {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
        self.doit(req).map_err(|e| Box::new(e) as Box<Error+Send>)
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(io, core, std_misc, path)]
#![cfg_attr(test, deny(warnings))]

extern crate conduit;
extern crate flate2;

use std::ascii::AsciiExt;
use std::collections::hash_map::{HashMap, Entry};
use std::error::Error;
use std::io::prelude::*;
use std::io;
use std::path::PathBuf;
use std::process::{Command, Child, Stdio};

use conduit::{Request, Response};
use flate2::read::GzDecoder;

pub struct Serve(pub PathBuf);

impl Serve {
    fn doit(&self, req: &mut Request) -> io::Result<Response> {
        let mut cmd = Command::new("git");
        cmd.arg("http-backend");

        // Required environment variables
        cmd.env("REQUEST_METHOD",
                &format!("{:?}", req.method()).as_slice().to_ascii_uppercase());
        cmd.env("GIT_PROJECT_ROOT", &self.0);
        cmd.env("PATH_INFO", req.path());
        cmd.env("REMOTE_USER", "");
        cmd.env("REMOTE_ADDR", &req.remote_ip().to_string());
        cmd.env("QUERY_STRING", req.query_string().unwrap_or(""));
        cmd.env("CONTENT_TYPE", header(req, "Content-Type"));
        cmd.stderr(Stdio::inherit())
           .stdout(Stdio::piped())
           .stdin(Stdio::piped());
        let mut p = try!(cmd.spawn());

        // Pass in the body of the request (if any)
        //
        // As part of the CGI interface we're required to take care of gzip'd
        // requests. I'm not totally sure that this sequential copy is the best
        // thing to do or actually correct...
        if header(req, "Content-Encoding") == "gzip" {
            let mut body = try!(GzDecoder::new(req.body()));
            try!(io::copy(&mut body, &mut p.stdin.take().unwrap()));
        } else {
            try!(io::copy(&mut req.body(), &mut p.stdin.take().unwrap()));
        }

        // Parse the headers coming out, and the pass through the rest of the
        // process back down the stack.
        //
        // Note that we have to be careful to not drop the process which will wait
        // for the process to exit (and we haven't read stdout)
        let mut rdr = io::BufReader::new(p.stdout.take().unwrap());

        let mut headers = HashMap::new();
        for line in rdr.by_ref().lines() {
            let line = try!(line);
            if line.as_slice() == "\r" { break }

            let mut parts = line.as_slice().splitn(2, ':');
            let key = parts.next().unwrap();
            let value = parts.next().unwrap();
            let value = &value[1 .. value.len() - 1];
            match headers.entry(key.to_string()) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Vec::new()),
            }.push(value.to_string());
        }

        let (status_code, status_desc) = {
            let line = headers.remove("Status").unwrap_or(Vec::new());
            let line = line.into_iter().next().unwrap_or(String::new());
            let mut parts = line.as_slice().splitn(1, ' ');
            (parts.next().unwrap_or("").parse().unwrap_or(200),
             match parts.next() {
                 Some("Not Found") => "Not Found",
                 _ => "Ok",
             })
        };

        struct ProcessAndBuffer<R> { _p: Child, buf: io::BufReader<R> }
        impl<R: Read> Read for ProcessAndBuffer<R> {
            fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
                self.buf.read(b)
            }
        }
        return Ok(Response {
            status: (status_code, status_desc),
            headers: headers,
            body: Box::new(ProcessAndBuffer { _p: p, buf: rdr }),
        });

        fn header<'a>(req: &'a Request, name: &str) -> &'a str {
            let h = req.headers().find(name).unwrap_or(Vec::new());
            h.as_slice().get(0).map(|s| *s).unwrap_or("")
        }
    }
}

impl conduit::Handler for Serve {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
        self.doit(req).map_err(|e| Box::new(e) as Box<Error+Send>)
    }
}
<|endoftext|>


<commit_before>//! Lettre is an email library that allows creating and sending messages. It provides:
//!
//! * An easy to use email builder
//! * Pluggable email transports
//! * Unicode support
//! * Secure defaults
//!
//! Lettre requires Rust 1.40 or newer.
//!
//! ## Optional features
//!
//! * **builder**: Message builder
//! * **file-transport**: Transport that write messages into a file
//! * **smtp-transport**: Transport over SMTP
//! * **sendmail-transport**: Transport over SMTP
//! * **rustls-tls**: TLS support with the `rustls` crate
//! * **native-tls**: TLS support with the `native-tls` crate
//! * **r2d2**: Connection pool for SMTP transport
//! * **log**: Logging using the `log` crate
//! * **serde**: Serialization/Deserialization of entities
//! * **hostname**: Ability to try to use actual hostname in SMTP transaction

#![doc(html_root_url = "https://docs.rs/lettre/0.10.0")]
#![doc(html_favicon_url = "https://lettre.at/favicon.png")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unsafe_code
)]

pub mod address;
pub mod error;
#[cfg(feature = "builder")]
pub mod message;
pub mod transport;

use crate::error::Error;
#[cfg(feature = "builder")]
pub use crate::message::{
    header::{self, Headers},
    EmailFormat, Mailbox, Mailboxes, Message,
};
#[cfg(feature = "file-transport")]
pub use crate::transport::file::FileTransport;
#[cfg(feature = "sendmail-transport")]
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::client::TlsParameters;
#[cfg(all(feature = "smtp-transport", feature = "connection-pool"))]
pub use crate::transport::smtp::r2d2::SmtpConnectionManager;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::{client::Tls, SmtpTransport};
pub use crate::{address::Address, transport::stub::StubTransport};
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
use async_trait::async_trait;
#[cfg(feature = "builder")]
use std::convert::TryFrom;
use std::{error::Error as StdError, fmt};

/// Simple email envelope representation
///
/// We only accept mailboxes, and do not support source routes (as per RFC).
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Envelope {
    /// The envelope recipients' addresses
    ///
    /// This can not be empty.
    forward_path: Vec<Address>,
    /// The envelope sender address
    reverse_path: Option<Address>,
}

impl Envelope {
    /// Creates a new envelope, which may fail if `to` is empty.
    pub fn new(from: Option<Address>, to: Vec<Address>) -> Result<Envelope, Error> {
        if to.is_empty() {
            return Err(Error::MissingTo);
        }
        Ok(Envelope {
            forward_path: to,
            reverse_path: from,
        })
    }

    /// Destination addresses of the envelope
    pub fn to(&self) -> &[Address] {
        self.forward_path.as_slice()
    }

    /// Source address of the envelope
    pub fn from(&self) -> Option<&Address> {
        self.reverse_path.as_ref()
    }
}

impl TryFrom<&Headers> for Envelope {
    type Error = Error;

    fn try_from(headers: &Headers) -> Result<Self, Self::Error> {
        let from = match headers.get::<header::Sender>() {
            // If there is a Sender, use it
            Some(header::Sender(a)) => Some(a.email.clone()),
            // ... else try From
            None => match headers.get::<header::From>() {
                Some(header::From(a)) => {
                    let from: Vec<Mailbox> = a.clone().into();
                    if from.len() > 1 {
                        return Err(Error::TooManyFrom);
                    }
                    Some(from[0].email.clone())
                }
                None => None,
            },
        };

        fn add_addresses_from_mailboxes(
            addresses: &mut Vec<Address>,
            mailboxes: Option<&Mailboxes>,
        ) {
            if let Some(mailboxes) = mailboxes {
                for mailbox in mailboxes.iter() {
                    addresses.push(mailbox.email.clone());
                }
            }
        }
        let mut to = vec![];
        add_addresses_from_mailboxes(&mut to, headers.get::<header::To>().map(|h| &h.0));
        add_addresses_from_mailboxes(&mut to, headers.get::<header::Cc>().map(|h| &h.0));
        add_addresses_from_mailboxes(&mut to, headers.get::<header::Bcc>().map(|h| &h.0));

        Self::new(from, to)
    }
}

/// Blocking Transport method for emails
pub trait Transport {
    /// Result types for the transport
    type Ok: fmt::Debug;
    type Error: StdError;

    /// Sends the email
    #[cfg(feature = "builder")]
    fn send(&self, message: &Message) -> Result<Self::Ok, Self::Error> {
        let raw = message.formatted();
        self.send_raw(message.envelope(), &raw)
    }

    fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}

/// async-std 1.x based Transport method for emails
#[cfg(feature = "async-std1")]
#[async_trait]
pub trait AsyncStd1Transport {
    /// Result types for the transport
    type Ok: fmt::Debug;
    type Error: StdError;

    /// Sends the email
    #[cfg(feature = "builder")]
    // TODO take &Message
    async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
        let raw = message.formatted();
        let envelope = message.envelope();
        self.send_raw(&envelope, &raw).await
    }

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}

/// tokio 0.2.x based Transport method for emails
#[cfg(feature = "tokio02")]
#[async_trait]
pub trait Tokio02Transport {
    /// Result types for the transport
    type Ok: fmt::Debug;
    type Error: StdError;

    /// Sends the email
    #[cfg(feature = "builder")]
    // TODO take &Message
    async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
        let raw = message.formatted();
        let envelope = message.envelope();
        self.send_raw(&envelope, &raw).await
    }

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::message::{header, Mailbox, Mailboxes};
    use hyperx::header::Headers;

    #[test]
    fn envelope_from_headers() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_sender() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo2", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_no_to() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));

        assert!(Envelope::try_from(&headers).is_err(),);
    }
}
<commit_msg>refactor: stop exporting TlsParameters and Tls as top-level<commit_after>//! Lettre is an email library that allows creating and sending messages. It provides:
//!
//! * An easy to use email builder
//! * Pluggable email transports
//! * Unicode support
//! * Secure defaults
//!
//! Lettre requires Rust 1.40 or newer.
//!
//! ## Optional features
//!
//! * **builder**: Message builder
//! * **file-transport**: Transport that write messages into a file
//! * **smtp-transport**: Transport over SMTP
//! * **sendmail-transport**: Transport over SMTP
//! * **rustls-tls**: TLS support with the `rustls` crate
//! * **native-tls**: TLS support with the `native-tls` crate
//! * **r2d2**: Connection pool for SMTP transport
//! * **log**: Logging using the `log` crate
//! * **serde**: Serialization/Deserialization of entities
//! * **hostname**: Ability to try to use actual hostname in SMTP transaction

#![doc(html_root_url = "https://docs.rs/lettre/0.10.0")]
#![doc(html_favicon_url = "https://lettre.at/favicon.png")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unsafe_code
)]

pub mod address;
pub mod error;
#[cfg(feature = "builder")]
pub mod message;
pub mod transport;

use crate::error::Error;
#[cfg(feature = "builder")]
pub use crate::message::{
    header::{self, Headers},
    EmailFormat, Mailbox, Mailboxes, Message,
};
#[cfg(feature = "file-transport")]
pub use crate::transport::file::FileTransport;
#[cfg(feature = "sendmail-transport")]
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(all(feature = "smtp-transport", feature = "connection-pool"))]
pub use crate::transport::smtp::r2d2::SmtpConnectionManager;
#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::SmtpTransport;
pub use crate::{address::Address, transport::stub::StubTransport};
#[cfg(any(feature = "async-std1", feature = "tokio02"))]
use async_trait::async_trait;
#[cfg(feature = "builder")]
use std::convert::TryFrom;
use std::{error::Error as StdError, fmt};

/// Simple email envelope representation
///
/// We only accept mailboxes, and do not support source routes (as per RFC).
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Envelope {
    /// The envelope recipients' addresses
    ///
    /// This can not be empty.
    forward_path: Vec<Address>,
    /// The envelope sender address
    reverse_path: Option<Address>,
}

impl Envelope {
    /// Creates a new envelope, which may fail if `to` is empty.
    pub fn new(from: Option<Address>, to: Vec<Address>) -> Result<Envelope, Error> {
        if to.is_empty() {
            return Err(Error::MissingTo);
        }
        Ok(Envelope {
            forward_path: to,
            reverse_path: from,
        })
    }

    /// Destination addresses of the envelope
    pub fn to(&self) -> &[Address] {
        self.forward_path.as_slice()
    }

    /// Source address of the envelope
    pub fn from(&self) -> Option<&Address> {
        self.reverse_path.as_ref()
    }
}

impl TryFrom<&Headers> for Envelope {
    type Error = Error;

    fn try_from(headers: &Headers) -> Result<Self, Self::Error> {
        let from = match headers.get::<header::Sender>() {
            // If there is a Sender, use it
            Some(header::Sender(a)) => Some(a.email.clone()),
            // ... else try From
            None => match headers.get::<header::From>() {
                Some(header::From(a)) => {
                    let from: Vec<Mailbox> = a.clone().into();
                    if from.len() > 1 {
                        return Err(Error::TooManyFrom);
                    }
                    Some(from[0].email.clone())
                }
                None => None,
            },
        };

        fn add_addresses_from_mailboxes(
            addresses: &mut Vec<Address>,
            mailboxes: Option<&Mailboxes>,
        ) {
            if let Some(mailboxes) = mailboxes {
                for mailbox in mailboxes.iter() {
                    addresses.push(mailbox.email.clone());
                }
            }
        }
        let mut to = vec![];
        add_addresses_from_mailboxes(&mut to, headers.get::<header::To>().map(|h| &h.0));
        add_addresses_from_mailboxes(&mut to, headers.get::<header::Cc>().map(|h| &h.0));
        add_addresses_from_mailboxes(&mut to, headers.get::<header::Bcc>().map(|h| &h.0));

        Self::new(from, to)
    }
}

/// Blocking Transport method for emails
pub trait Transport {
    /// Result types for the transport
    type Ok: fmt::Debug;
    type Error: StdError;

    /// Sends the email
    #[cfg(feature = "builder")]
    fn send(&self, message: &Message) -> Result<Self::Ok, Self::Error> {
        let raw = message.formatted();
        self.send_raw(message.envelope(), &raw)
    }

    fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}

/// async-std 1.x based Transport method for emails
#[cfg(feature = "async-std1")]
#[async_trait]
pub trait AsyncStd1Transport {
    /// Result types for the transport
    type Ok: fmt::Debug;
    type Error: StdError;

    /// Sends the email
    #[cfg(feature = "builder")]
    // TODO take &Message
    async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
        let raw = message.formatted();
        let envelope = message.envelope();
        self.send_raw(&envelope, &raw).await
    }

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}

/// tokio 0.2.x based Transport method for emails
#[cfg(feature = "tokio02")]
#[async_trait]
pub trait Tokio02Transport {
    /// Result types for the transport
    type Ok: fmt::Debug;
    type Error: StdError;

    /// Sends the email
    #[cfg(feature = "builder")]
    // TODO take &Message
    async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
        let raw = message.formatted();
        let envelope = message.envelope();
        self.send_raw(&envelope, &raw).await
    }

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::message::{header, Mailbox, Mailboxes};
    use hyperx::header::Headers;

    #[test]
    fn envelope_from_headers() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_sender() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo2", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_no_to() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));

        assert!(Envelope::try_from(&headers).is_err(),);
    }
}
<|endoftext|>


<commit_before>// Copyright(C) 2016 Chris Liebert

#![crate_type = "lib"]
#![crate_name = "quick3d"]
#![allow(dead_code)]
#[macro_use]
extern crate glium;
extern crate rustc_serialize;
extern crate bincode;
extern crate flate2;

pub mod frustum;
pub mod common;
pub mod dbloader;
pub mod input;
pub mod camera;
pub mod scene;
pub mod shader;
#[macro_use]
pub mod renderer;

extern crate nalgebra;
extern crate libc;

use std::ffi::CStr;

use glium::glutin;
use glium::DisplayBuild;
use glium::backend::glutin_backend::GlutinFacade;

#[cfg(feature = "sqlite")]
use dbloader::DBLoader;

#[cfg(feature = "sqlite")]
use scene::Scene;

#[cfg(feature = "sqlite")]
#[link(name = "tinyobjloader", kind="static")]
#[link(name = "scenebuilder", kind="static")]
#[link(name = "stdc++")]
extern "C" {
    fn wavefrontToSQLite(wavefront_file: *const libc::c_char, database_file: *const libc::c_char);
}

/// The following methods annotated as #[no_mangle] provide external interfaces
/// that can be accessed from C and SWIG
///

/// `extern void obj2sqlite(const char* wavefront, const char* database);`
///
/// If the obj2sqlite feature is enabled, a bundled c++ library is used.
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub fn obj2sqlite(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    unsafe { wavefrontToSQLite(wavefront_file, database_file) };
}

/// `extern void obj2sqlite(const char* wavefront, const char* database);`
///
/// When the sqlite feature is disabled, the method is still availible
/// so that the FFI wrappers will still build without modification the user
/// is notified that the feature is disabled.
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub fn obj2sqlite(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    let filename1: String = unsafe{ CStr::from_ptr(wavefront_file).to_string_lossy().into_owned() };
    let filename2: String = unsafe{ CStr::from_ptr(database_file).to_string_lossy().into_owned() };
    panic!("Unable to convert {} to {}, the SQLite feature is not enabled.", filename1, filename2);
}

/// `extern void obj2bin(const char* wavefront, const char* database);`
///
/// This will print an error if the sqlite feature is disabled
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub fn obj2bin(wavefront_file: *const libc::c_char, binfile: *const libc::c_char) {
    use std::ffi::CString;
    let filename: String = unsafe{ CStr::from_ptr(wavefront_file.clone()).to_string_lossy().into_owned() };
    let binfile_str: String = unsafe{ CStr::from_ptr(binfile.clone()).to_string_lossy().into_owned() };
    let mut database_file: String = filename.clone();
    database_file.push_str(&String::from(".db"));
    let sqlite_file = CString::new(database_file.clone()).unwrap();
    obj2sqlite(wavefront_file, sqlite_file.clone().into_raw());
    let scene: Scene = match DBLoader::new(&(sqlite_file.into_string().unwrap())).unwrap().load_scene() {
        Ok(s) => s,
        Err(e) => panic!("Unable to load scene from SQLite: {:?}", e),
    };
    match scene.to_binary_file(binfile_str.clone()) {
        Ok(()) => println!("Saved {}", binfile_str),
        Err(e) => panic!("Unable to save binary file {}: {:?}", binfile_str, e),
    };
}

/// `extern void obj2bin(const char* wavefront, const char* database);`
///
/// When the sqlite feature is disabled, the method is still availible
/// so that the FFI wrappers will still build without modification the user
/// is notified that the feature is disabled.
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub fn obj2bin(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    let filename1: String = unsafe{ CStr::from_ptr(wavefront_file).to_string_lossy().into_owned() };
    let filename2: String = unsafe{ CStr::from_ptr(database_file).to_string_lossy().into_owned() };
    panic!("Unable to convert {} to {}, the SQLite feature is not enabled.", filename1, filename2);
}

/// `extern void obj2compressed(const char* wavefront, const char* database);`
///
/// This will print an error if the obj2sqlite feature is disabled
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub fn obj2compressed(wavefront_file: *const libc::c_char, binfile: *const libc::c_char) {
    use std::ffi::CString;
	let filename: String = unsafe{ CStr::from_ptr(wavefront_file.clone()).to_string_lossy().into_owned() };
    let binfile_str: String = unsafe{ CStr::from_ptr(binfile.clone()).to_string_lossy().into_owned() };
    let mut database_file: String = filename.clone();
    database_file.push_str(&String::from(".db"));
    let sqlite_file = CString::new(database_file.clone()).unwrap();
    obj2sqlite(wavefront_file, sqlite_file.clone().into_raw());
    let scene: Scene = match DBLoader::new(&(sqlite_file.into_string().unwrap())).unwrap().load_scene() {
        Ok(s) => s,
        Err(e) => panic!("Unable to load scene from SQLite: {:?}", e),
    };
    match scene.to_compressed_binary_file(binfile_str.clone()) {
        Ok(()) => println!("Saved {}", binfile_str),
        Err(e) => panic!("Unable to save compressed binary file {}: {:?}", binfile_str, e),
    };
}

/// `extern void obj2compressed(const char* wavefront, const char* database);`
///
/// When the sqlite feature is disabled, the method is still availible
/// so that the FFI wrappers will still build without modification the user
/// is notified that the feature is disabled.
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub fn obj2compressed(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    let filename1: String = unsafe{ CStr::from_ptr(wavefront_file).to_string_lossy().into_owned() };
    let filename2: String = unsafe{ CStr::from_ptr(database_file).to_string_lossy().into_owned() };
    panic!("Unable to convert {} to {}, the SQLite feature is not enabled.", filename1, filename2);
}

/// `extern Display create_display(int screen_width, int screen_height, const char* title);`
///
#[no_mangle]
pub extern "C" fn create_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const libc::c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {
        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
            .with_gl_debug_flag(true)
            .with_title(window_title)
            .with_visibility(true)
            .with_dimensions(w, h)
            .build_glium()
            .unwrap();
        return Box::new(display);
    }
}

/// `extern Display create_hidden_display(int screen_width, int screen_height, const char* title);`
///
#[no_mangle]
pub extern "C" fn create_hidden_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const libc::c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {

        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
            .with_gl_debug_flag(true)
            .with_title(window_title)
            .with_visibility(false)
            .with_dimensions(w, h)
            .build_glium()
            .unwrap();
        return Box::new(display);
    }
}

/// `extern void free_display(Display memory);`
///
#[no_mangle]
pub extern "C" fn free_display(ptr: *mut GlutinFacade) {
    let box_ptr: Box<GlutinFacade> = unsafe { Box::from_raw(ptr) };
    drop(box_ptr)
}

use std::time::Duration;

/// `extern void thread_sleep(int ms);`
///
#[no_mangle]
pub extern "C" fn thread_sleep(ms: libc::int32_t) {
    std::thread::sleep(Duration::from_millis(ms as u64));
}

/// `extern void thread_yield();`
///
#[no_mangle]
pub extern "C" fn thread_yield() {
    std::thread::yield_now();
}

/// `extern void window_hide(Display display);`
///
#[no_mangle]
pub extern "C" fn window_hide(display: &GlutinFacade) {
    match display.get_window() {
        Some(w) => {
            w.hide();
        }
        None => {
            panic!("Error retrieving window");
        }
    };
}

/// `extern void window_show(Display display);`
///
#[no_mangle]
pub extern "C" fn window_show(display: &GlutinFacade) {
    match display.get_window() {
        Some(w) => {
            w.show();
        }
        None => {
            panic!("Error retrieving window");
        }
    };
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use std::thread;
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use scene::Scene;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        Scene::from_compressed_binary_file(String::from("test.bin.gz")).unwrap()
    }

    #[test]
    fn test_scene_not_empty() {
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
    }

    #[test]
    fn display_creation() {
        // Opens a window for 100 miliseconds
        let display = create_test_display();
        let window = match display.get_window() {
            Some(w) => {
                w
            }
            None => {
                panic!("Error retrieving window");
            }
        };
        window.show();
        thread::sleep(Duration::from_millis(100));
    }

	#[cfg(feature = "sqlite")]
    #[test]
    fn renderer() {
    	use dbloader::DBLoader;
		use camera::Camera;
		use renderer::Renderer;
		use shader::Shader;
        // Opens a window for 100 miliseconds and draws the contents of test.db
        let display = create_test_display();
        let window = match display.get_window() {
            Some(w) => {
                w
            }
            None => {
                panic!("Error retrieving window");
            }
        };
        window.show();
        let window_size = window.get_inner_size().unwrap();
        let screen_width = window_size.0;
        let screen_height = window_size.1;
        let mut camera = Camera::new(screen_width as f32, screen_height as f32);
        camera = camera.move_backward(6.0);

        let scene = load_test_scene();
        let renderer = Renderer::new(&display, scene).unwrap();

        let shader_dbloader = DBLoader::new("shaders.db").unwrap();
        let shader_name = "default";
        let shader_program = Shader::from_dbloader(&shader_name, &shader_dbloader, &display).unwrap();

        renderer.render(&display, &shader_program, &camera).unwrap();

        thread::sleep(Duration::from_millis(100));
    }

	#[cfg(feature = "sqlite")]
    #[test]
    fn test_compressed_binary_scene() {
    	use dbloader::DBLoader;
		use camera::Camera;
		use renderer::Renderer;
		use shader::Shader;
        // Opens a window for 100 miliseconds and draws the contents of test.bin
        let display = create_test_display();
        let window = match display.get_window() {
            Some(w) => {
                w
            }
            None => {
                panic!("Error retrieving window");
            }
        };
        window.show();
        let window_size = window.get_inner_size().unwrap();
        let screen_width = window_size.0;
        let screen_height = window_size.1;
        let mut camera = Camera::new(screen_width as f32, screen_height as f32);
        camera = camera.move_backward(6.0);

        let scene = load_test_scene();

        let binfile_name = String::from("test.bin");
        match scene.to_compressed_binary_file(binfile_name.clone()) {
            Ok(_) => (),
            Err(e) => panic!("Unable to save binary file {}: {:?}", binfile_name.clone(), e),
        };

        let scene_binary: Scene =  match Scene::from_compressed_binary_file(binfile_name.clone()) {
            Ok(s) => s,
            Err(e) => panic!("Unable to load binary scene from {}: {:?}", binfile_name.clone(), e),
        };

        assert!(scene == scene_binary);
        drop(scene);

        let renderer: Renderer = Renderer::new(&display, scene_binary).unwrap();

        let shader_dbloader = DBLoader::new("shaders.db").unwrap();
        let shader_name = "default";
        let shader_program = Shader::from_dbloader(&shader_name, &shader_dbloader, &display).unwrap();

        renderer.render(&display, &shader_program, &camera).unwrap();

        thread::sleep(Duration::from_millis(100));
    }
}
<commit_msg>improved error handling for display creation<commit_after>// Copyright(C) 2016 Chris Liebert

#![crate_type = "lib"]
#![crate_name = "quick3d"]
#![allow(dead_code)]
#[macro_use]
extern crate glium;
extern crate rustc_serialize;
extern crate bincode;
extern crate flate2;

pub mod frustum;
pub mod common;
pub mod dbloader;
pub mod input;
pub mod camera;
pub mod scene;
pub mod shader;
#[macro_use]
pub mod renderer;

extern crate nalgebra;
extern crate libc;

use std::ffi::CStr;

use glium::glutin;
use glium::DisplayBuild;
use glium::backend::glutin_backend::GlutinFacade;

#[cfg(feature = "sqlite")]
use dbloader::DBLoader;

#[cfg(feature = "sqlite")]
use scene::Scene;

#[cfg(feature = "sqlite")]
#[link(name = "tinyobjloader", kind="static")]
#[link(name = "scenebuilder", kind="static")]
#[link(name = "stdc++")]
extern "C" {
    fn wavefrontToSQLite(wavefront_file: *const libc::c_char, database_file: *const libc::c_char);
}

/// The following methods annotated as #[no_mangle] provide external interfaces
/// that can be accessed from C and SWIG
///

/// `extern void obj2sqlite(const char* wavefront, const char* database);`
///
/// If the obj2sqlite feature is enabled, a bundled c++ library is used.
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub fn obj2sqlite(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    unsafe { wavefrontToSQLite(wavefront_file, database_file) };
}

/// `extern void obj2sqlite(const char* wavefront, const char* database);`
///
/// When the sqlite feature is disabled, the method is still availible
/// so that the FFI wrappers will still build without modification the user
/// is notified that the feature is disabled.
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub fn obj2sqlite(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    let filename1: String = unsafe{ CStr::from_ptr(wavefront_file).to_string_lossy().into_owned() };
    let filename2: String = unsafe{ CStr::from_ptr(database_file).to_string_lossy().into_owned() };
    panic!("Unable to convert {} to {}, the SQLite feature is not enabled.", filename1, filename2);
}

/// `extern void obj2bin(const char* wavefront, const char* database);`
///
/// This will print an error if the sqlite feature is disabled
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub fn obj2bin(wavefront_file: *const libc::c_char, binfile: *const libc::c_char) {
    use std::ffi::CString;
    let filename: String = unsafe{ CStr::from_ptr(wavefront_file.clone()).to_string_lossy().into_owned() };
    let binfile_str: String = unsafe{ CStr::from_ptr(binfile.clone()).to_string_lossy().into_owned() };
    let mut database_file: String = filename.clone();
    database_file.push_str(&String::from(".db"));
    let sqlite_file = CString::new(database_file.clone()).unwrap();
    obj2sqlite(wavefront_file, sqlite_file.clone().into_raw());
    let scene: Scene = match DBLoader::new(&(sqlite_file.into_string().unwrap())).unwrap().load_scene() {
        Ok(s) => s,
        Err(e) => panic!("Unable to load scene from SQLite: {:?}", e),
    };
    match scene.to_binary_file(binfile_str.clone()) {
        Ok(()) => println!("Saved {}", binfile_str),
        Err(e) => panic!("Unable to save binary file {}: {:?}", binfile_str, e),
    };
}

/// `extern void obj2bin(const char* wavefront, const char* database);`
///
/// When the sqlite feature is disabled, the method is still availible
/// so that the FFI wrappers will still build without modification the user
/// is notified that the feature is disabled.
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub fn obj2bin(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    let filename1: String = unsafe{ CStr::from_ptr(wavefront_file).to_string_lossy().into_owned() };
    let filename2: String = unsafe{ CStr::from_ptr(database_file).to_string_lossy().into_owned() };
    panic!("Unable to convert {} to {}, the SQLite feature is not enabled.", filename1, filename2);
}

/// `extern void obj2compressed(const char* wavefront, const char* database);`
///
/// This will print an error if the obj2sqlite feature is disabled
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub fn obj2compressed(wavefront_file: *const libc::c_char, binfile: *const libc::c_char) {
    use std::ffi::CString;
	let filename: String = unsafe{ CStr::from_ptr(wavefront_file.clone()).to_string_lossy().into_owned() };
    let binfile_str: String = unsafe{ CStr::from_ptr(binfile.clone()).to_string_lossy().into_owned() };
    let mut database_file: String = filename.clone();
    database_file.push_str(&String::from(".db"));
    let sqlite_file = CString::new(database_file.clone()).unwrap();
    obj2sqlite(wavefront_file, sqlite_file.clone().into_raw());
    let scene: Scene = match DBLoader::new(&(sqlite_file.into_string().unwrap())).unwrap().load_scene() {
        Ok(s) => s,
        Err(e) => panic!("Unable to load scene from SQLite: {:?}", e),
    };
    match scene.to_compressed_binary_file(binfile_str.clone()) {
        Ok(()) => println!("Saved {}", binfile_str),
        Err(e) => panic!("Unable to save compressed binary file {}: {:?}", binfile_str, e),
    };
}

/// `extern void obj2compressed(const char* wavefront, const char* database);`
///
/// When the sqlite feature is disabled, the method is still availible
/// so that the FFI wrappers will still build without modification the user
/// is notified that the feature is disabled.
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub fn obj2compressed(wavefront_file: *const libc::c_char, database_file: *const libc::c_char) {
    let filename1: String = unsafe{ CStr::from_ptr(wavefront_file).to_string_lossy().into_owned() };
    let filename2: String = unsafe{ CStr::from_ptr(database_file).to_string_lossy().into_owned() };
    panic!("Unable to convert {} to {}, the SQLite feature is not enabled.", filename1, filename2);
}

/// `extern Display create_display(int screen_width, int screen_height, const char* title);`
///
#[no_mangle]
pub extern "C" fn create_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const libc::c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    //let window_title: String;

    unsafe {
        //window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
            //.with_gl_debug_flag(true)
            //.with_title(window_title)
            .with_visibility(true)
            //.with_dimensions(w, h)
            .with_multitouch()
						.build_glium_unchecked()
            .expect("Unable to create display");
        return Box::new(display);
    }
}

/// `extern Display create_hidden_display(int screen_width, int screen_height, const char* title);`
///
#[no_mangle]
pub extern "C" fn create_hidden_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const libc::c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {

        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
            .with_gl_debug_flag(true)
            .with_title(window_title)
            .with_visibility(false)
            .with_dimensions(w, h)
            .build_glium()
            .expect("Unable to create display");
        return Box::new(display);
    }
}

/// `extern void free_display(Display memory);`
///
#[no_mangle]
pub extern "C" fn free_display(ptr: *mut GlutinFacade) {
    let box_ptr: Box<GlutinFacade> = unsafe { Box::from_raw(ptr) };
    drop(box_ptr)
}

use std::time::Duration;

/// `extern void thread_sleep(int ms);`
///
#[no_mangle]
pub extern "C" fn thread_sleep(ms: libc::int32_t) {
    std::thread::sleep(Duration::from_millis(ms as u64));
}

/// `extern void thread_yield();`
///
#[no_mangle]
pub extern "C" fn thread_yield() {
    std::thread::yield_now();
}

/// `extern void window_hide(Display display);`
///
#[no_mangle]
pub extern "C" fn window_hide(display: &GlutinFacade) {
    match display.get_window() {
        Some(w) => {
            w.hide();
        }
        None => {
            panic!("Error retrieving window");
        }
    };
}

/// `extern void window_show(Display display);`
///
#[no_mangle]
pub extern "C" fn window_show(display: &GlutinFacade) {
    match display.get_window() {
        Some(w) => {
            w.show();
        }
        None => {
            panic!("Error retrieving window");
        }
    };
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use std::thread;
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use scene::Scene;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        Scene::from_compressed_binary_file(String::from("test.bin.gz")).unwrap()
    }

    #[test]
    fn test_scene_not_empty() {
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
    }

    #[test]
    fn display_creation() {
        // Opens a window for 100 miliseconds
        let display = create_test_display();
        let window = match display.get_window() {
            Some(w) => {
                w
            }
            None => {
                panic!("Error retrieving window");
            }
        };
        window.show();
        thread::sleep(Duration::from_millis(100));
    }

	#[cfg(feature = "sqlite")]
    #[test]
    fn renderer() {
    	use dbloader::DBLoader;
		use camera::Camera;
		use renderer::Renderer;
		use shader::Shader;
        // Opens a window for 100 miliseconds and draws the contents of test.db
        let display = create_test_display();
        let window = match display.get_window() {
            Some(w) => {
                w
            }
            None => {
                panic!("Error retrieving window");
            }
        };
        window.show();
        let window_size = window.get_inner_size().unwrap();
        let screen_width = window_size.0;
        let screen_height = window_size.1;
        let mut camera = Camera::new(screen_width as f32, screen_height as f32);
        camera = camera.move_backward(6.0);

        let scene = load_test_scene();
        let renderer = Renderer::new(&display, scene).unwrap();

        let shader_dbloader = DBLoader::new("shaders.db").unwrap();
        let shader_name = "default";
        let shader_program = Shader::from_dbloader(&shader_name, &shader_dbloader, &display).unwrap();

        renderer.render(&display, &shader_program, &camera).unwrap();

        thread::sleep(Duration::from_millis(100));
    }

	#[cfg(feature = "sqlite")]
    #[test]
    fn test_compressed_binary_scene() {
    	use dbloader::DBLoader;
		use camera::Camera;
		use renderer::Renderer;
		use shader::Shader;
        // Opens a window for 100 miliseconds and draws the contents of test.bin
        let display = create_test_display();
        let window = match display.get_window() {
            Some(w) => {
                w
            }
            None => {
                panic!("Error retrieving window");
            }
        };
        window.show();
        let window_size = window.get_inner_size().unwrap();
        let screen_width = window_size.0;
        let screen_height = window_size.1;
        let mut camera = Camera::new(screen_width as f32, screen_height as f32);
        camera = camera.move_backward(6.0);

        let scene = load_test_scene();

        let binfile_name = String::from("test.bin");
        match scene.to_compressed_binary_file(binfile_name.clone()) {
            Ok(_) => (),
            Err(e) => panic!("Unable to save binary file {}: {:?}", binfile_name.clone(), e),
        };

        let scene_binary: Scene =  match Scene::from_compressed_binary_file(binfile_name.clone()) {
            Ok(s) => s,
            Err(e) => panic!("Unable to load binary scene from {}: {:?}", binfile_name.clone(), e),
        };

        assert!(scene == scene_binary);
        drop(scene);

        let renderer: Renderer = Renderer::new(&display, scene_binary).unwrap();

        let shader_dbloader = DBLoader::new("shaders.db").unwrap();
        let shader_name = "default";
        let shader_program = Shader::from_dbloader(&shader_name, &shader_dbloader, &display).unwrap();

        renderer.render(&display, &shader_program, &camera).unwrap();

        thread::sleep(Duration::from_millis(100));
    }
}
<|endoftext|>


<commit_before>//! A library providing a generic connection pool.
#![feature(unsafe_destructor)]
#![warn(missing_docs)]
#![allow(unstable)]
#![doc(html_root_url="https://sfackler.github.io/doc")]

#[macro_use]
extern crate log;
extern crate time;

use std::collections::RingBuf;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Condvar};
use std::fmt;

pub use config::{Config, ConfigError};

use task::ScheduledThreadPool;

mod config;
mod task;

/// A trait which provides database-specific functionality.
pub trait PoolManager<C, E>: Send+Sync {
    /// Attempts to create a new connection.
    fn connect(&self) -> Result<C, E>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut C) -> Result<(), E>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut C) -> bool;
}

/// A trait which handles errors reported by the `PoolManager`.
pub trait ErrorHandler<E>: Send+Sync {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

impl<E> ErrorHandler<E> for Box<ErrorHandler<E>> {
    fn handle_error(&self, error: E) {
        (**self).handle_error(error)
    }
}

/// An `ErrorHandler` which does nothing.
#[derive(Copy, Clone, Show)]
pub struct NoopErrorHandler;

impl<E> ErrorHandler<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// An `ErrorHandler` which logs at the error level.
#[derive(Copy, Clone, Show)]
pub struct LoggingErrorHandler;

impl<E> ErrorHandler<E> for LoggingErrorHandler where E: fmt::Show {
    fn handle_error(&self, error: E) {
        error!("{:?}", error);
    }
}

struct PoolInternals<C> {
    conns: RingBuf<C>,
    num_conns: u32,
    thread_pool: ScheduledThreadPool,
}

unsafe impl<C: Send> Send for PoolInternals<C> {}

struct SharedPool<C, E, M, H> where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    config: Config,
    manager: M,
    error_handler: H,
    internals: Mutex<PoolInternals<C>>,
    cond: Condvar,
}

fn add_connection<C, E, M, H>(inner: &Arc<SharedPool<C, E, M, H>>)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    let new_inner = inner.clone();
    inner.internals.lock().unwrap().thread_pool.run(move || {
        let inner = new_inner;
        match inner.manager.connect() {
            Ok(conn) => {
                let mut internals = inner.internals.lock().unwrap();
                internals.conns.push_back(conn);
                internals.num_conns += 1;
                inner.cond.notify_one();
            }
            Err(err) => inner.error_handler.handle_error(err),
        }
    });
}

/// A generic connection pool.
pub struct Pool<C, E, M, H> where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    inner: Arc<SharedPool<C, E, M, H>>,
}

impl<C, E, M, H> fmt::Show for Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>+fmt::Show, H: ErrorHandler<E> {
    // FIXME there's more we can do here
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Pool {{ config: {:?}, manager: {:?} }}", self.inner.config,
               self.inner.manager)
    }
}

impl<C, E, M, H> Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value only if `config` is invalid.
    pub fn new(config: Config, manager: M, error_handler: H)
               -> Result<Pool<C, E, M, H>, ConfigError> {
        try!(config.validate());

        let internals = PoolInternals {
            conns: RingBuf::new(),
            num_conns: config.pool_size,
            thread_pool: ScheduledThreadPool::new(config.helper_tasks as usize),
        };

        let inner = Arc::new(SharedPool {
            config: config,
            manager: manager,
            error_handler: error_handler,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        for _ in range(0, config.pool_size) {
            add_connection(&inner);
        }

        Ok(Pool {
            inner: inner,
        })
    }

    /// Retrieves a connection from the pool.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, C, E, M, H>, ()> {
        let mut internals = self.inner.internals.lock().unwrap();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.inner.config.test_on_check_out {
                        if let Err(e) = self.inner.manager.is_valid(&mut conn) {
                            self.inner.error_handler.handle_error(e);
                            internals = self.inner.internals.lock().unwrap();
                            internals.num_conns -= 1;
                            continue
                        }
                    }

                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn),
                    })
                }
                None => {
                    internals = self.inner.cond.wait(internals).unwrap();
                }
            }
        }
    }

    fn put_back(&self, mut conn: C) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.inner.manager.has_broken(&mut conn);

        let mut internals = self.inner.internals.lock().unwrap();
        if broken {
            internals.num_conns -= 1;
        } else {
            internals.conns.push_back(conn);
            self.inner.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    pool: &'a Pool<C, E, M, H>,
    conn: Option<C>,
}

impl<'a, C, E, M, H> fmt::Show for PooledConnection<'a, C, E, M, H>
        where C: Send+fmt::Show, E: Send, M: PoolManager<C, E>+fmt::Show, H: ErrorHandler<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PooledConnection {{ pool: {:?}, connection: {:?} }}", self.pool,
               self.conn.as_ref().unwrap())
    }
}

#[unsafe_destructor]
impl<'a, C, E, M, H> Drop for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<'a, C, E, M, H> Deref for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    type Target = C;

    fn deref(&self) -> &C {
        self.conn.as_ref().unwrap()
    }
}

impl<'a, C, E, M, H> DerefMut for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn deref_mut(&mut self) -> &mut C {
        self.conn.as_mut().unwrap()
    }
}
<commit_msg>Rename shared pool references<commit_after>//! A library providing a generic connection pool.
#![feature(unsafe_destructor)]
#![warn(missing_docs)]
#![allow(unstable)]
#![doc(html_root_url="https://sfackler.github.io/doc")]

#[macro_use]
extern crate log;
extern crate time;

use std::collections::RingBuf;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Condvar};
use std::fmt;

pub use config::{Config, ConfigError};

use task::ScheduledThreadPool;

mod config;
mod task;

/// A trait which provides database-specific functionality.
pub trait PoolManager<C, E>: Send+Sync {
    /// Attempts to create a new connection.
    fn connect(&self) -> Result<C, E>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut C) -> Result<(), E>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut C) -> bool;
}

/// A trait which handles errors reported by the `PoolManager`.
pub trait ErrorHandler<E>: Send+Sync {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

impl<E> ErrorHandler<E> for Box<ErrorHandler<E>> {
    fn handle_error(&self, error: E) {
        (**self).handle_error(error)
    }
}

/// An `ErrorHandler` which does nothing.
#[derive(Copy, Clone, Show)]
pub struct NoopErrorHandler;

impl<E> ErrorHandler<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// An `ErrorHandler` which logs at the error level.
#[derive(Copy, Clone, Show)]
pub struct LoggingErrorHandler;

impl<E> ErrorHandler<E> for LoggingErrorHandler where E: fmt::Show {
    fn handle_error(&self, error: E) {
        error!("{:?}", error);
    }
}

struct PoolInternals<C> {
    conns: RingBuf<C>,
    num_conns: u32,
    thread_pool: ScheduledThreadPool,
}

unsafe impl<C: Send> Send for PoolInternals<C> {}

struct SharedPool<C, E, M, H> where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    config: Config,
    manager: M,
    error_handler: H,
    internals: Mutex<PoolInternals<C>>,
    cond: Condvar,
}

fn add_connection<C, E, M, H>(shared: &Arc<SharedPool<C, E, M, H>>)
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    let new_shared = shared.clone();
    shared.internals.lock().unwrap().thread_pool.run(move || {
        let shared = new_shared;
        match shared.manager.connect() {
            Ok(conn) => {
                let mut internals = shared.internals.lock().unwrap();
                internals.conns.push_back(conn);
                internals.num_conns += 1;
                shared.cond.notify_one();
            }
            Err(err) => shared.error_handler.handle_error(err),
        }
    });
}

/// A generic connection pool.
pub struct Pool<C, E, M, H> where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    shared: Arc<SharedPool<C, E, M, H>>,
}

impl<C, E, M, H> fmt::Show for Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>+fmt::Show, H: ErrorHandler<E> {
    // FIXME there's more we can do here
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Pool {{ config: {:?}, manager: {:?} }}", self.shared.config,
               self.shared.manager)
    }
}

impl<C, E, M, H> Pool<C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value only if `config` is invalid.
    pub fn new(config: Config, manager: M, error_handler: H)
               -> Result<Pool<C, E, M, H>, ConfigError> {
        try!(config.validate());

        let internals = PoolInternals {
            conns: RingBuf::new(),
            num_conns: config.pool_size,
            thread_pool: ScheduledThreadPool::new(config.helper_tasks as usize),
        };

        let shared = Arc::new(SharedPool {
            config: config,
            manager: manager,
            error_handler: error_handler,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        for _ in range(0, config.pool_size) {
            add_connection(&shared);
        }

        Ok(Pool {
            shared: shared,
        })
    }

    /// Retrieves a connection from the pool.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, C, E, M, H>, ()> {
        let mut internals = self.shared.internals.lock().unwrap();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn) {
                            self.shared.error_handler.handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            internals.num_conns -= 1;
                            continue
                        }
                    }

                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn),
                    })
                }
                None => {
                    internals = self.shared.cond.wait(internals).unwrap();
                }
            }
        }
    }

    fn put_back(&self, mut conn: C) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            internals.num_conns -= 1;
        } else {
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    pool: &'a Pool<C, E, M, H>,
    conn: Option<C>,
}

impl<'a, C, E, M, H> fmt::Show for PooledConnection<'a, C, E, M, H>
        where C: Send+fmt::Show, E: Send, M: PoolManager<C, E>+fmt::Show, H: ErrorHandler<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PooledConnection {{ pool: {:?}, connection: {:?} }}", self.pool,
               self.conn.as_ref().unwrap())
    }
}

#[unsafe_destructor]
impl<'a, C, E, M, H> Drop for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<'a, C, E, M, H> Deref for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    type Target = C;

    fn deref(&self) -> &C {
        self.conn.as_ref().unwrap()
    }
}

impl<'a, C, E, M, H> DerefMut for PooledConnection<'a, C, E, M, H>
        where C: Send, E: Send, M: PoolManager<C, E>, H: ErrorHandler<E> {
    fn deref_mut(&mut self) -> &mut C {
        self.conn.as_mut().unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate audsp;
extern crate aunorm;
use aunorm::{Normalizer, NormalizerProvider};
use std::collections::HashMap;

pub trait DspProcessor<'a, TSample: audsp::Numeric> {
    fn get_properties(& self) -> & PropStorage<'a, TSample, Self>;
    fn get_mut_properties(&mut self) -> &mut PropStorage<'a, TSample, Self>;
    fn param_changed(&mut self, i32);
    fn sample_rate_changed(&mut self, f32);
    fn get_plugin_name(&self) -> String;
    fn process_stereo_stereo(&mut self, [& [TSample]; 2], [&mut [TSample]; 2]);
}

#[allow(dead_code)]
pub struct PropInfo<'a, TSample: audsp::Numeric, TProcessor: DspProcessor<'a, TSample>> where TSample: 'a {
    id: u32,
    min: TSample,
    max: TSample,
    default: TSample,
    value: TSample,
    norm_value: TSample,
    caption: &'a str,
    measure: &'a str,
    norm: Box<Normalizer<TSample> + 'a>,
    callback : Box<Fn(&mut TProcessor) + 'a>,
}

#[derive(Default)]
pub struct PropStorage<'a, TSample: audsp::Numeric, TProcessor: DspProcessor<'a, TSample>> where TSample: 'a {
    properties: HashMap<u32, PropInfo<'a, TSample, TProcessor>>
}

impl<'a, TSample: audsp::Numeric, TProcessor: DspProcessor<'a, TSample>> PropInfo<'a, TSample, TProcessor> where TSample: 'a {
    pub fn set_from_norm(&mut self, norm: TSample, processor: &mut TProcessor) {
        self.norm_value = norm;
        self.value = self.norm.from_normal(norm);

        let callback = &self.callback;
        callback(processor);
    }

    pub fn get_value(&self) -> TSample {
        return self.value
    }

    pub fn get_norm_value(&self) -> TSample {
        return self.norm_value
    }

    pub fn get_caption(&self) -> String {
        self.caption.to_string()
    }

    pub fn get_measure(&self) -> String {
        self.measure.to_string()
    }
}

impl<'a, TSample: audsp::Numeric, TProcessor> PropStorage<'a, TSample, TProcessor> where TSample: 'a, TProcessor: DspProcessor<'a, TSample> {
    pub fn new() -> Self {
        PropStorage::<TSample, TProcessor>{properties: HashMap::new()}
    }

    pub fn len(&self) -> usize {
        self.properties.len()
    }

    pub fn add_prop<TProv>(&mut self, index: u32, min: TSample, max: TSample, default: TSample, caption: &'a str, measure: &'a str, callback: Box<Fn(&mut TProcessor) + 'a>) where TProv: NormalizerProvider<'a, TSample> {
        let norm = TProv::boxed(min, max);

        self.properties.insert(index, PropInfo::<TSample, TProcessor>{
            id: index,
            min: min,
            max: max,
            default: default,
            value: default,
            norm_value: norm.to_normal(default),
            caption: caption,
            measure: measure,
            norm: norm,
            callback: callback,
            });
    }

    pub fn get_value(&self, i: u32) -> TSample {
        return self.properties.get(&i).map(|x| x.value).unwrap_or(TSample::zero())
    }

    pub fn get_propinfo(&self, index: i32) -> Option<&PropInfo<TSample, TProcessor>> {
        let i:u32 = index as u32;
        self.properties.get(&i)
    }

    pub fn get_mut_propinfo(&mut self, index: i32) -> Option<&mut PropInfo<'a, TSample, TProcessor>> {
        let i:u32 = index as u32;
        self.properties.get_mut(&i)
    }
}
<commit_msg>ffs..<commit_after>extern crate audsp;
extern crate aunorm;
use aunorm::{Normalizer, NormalizerProvider};
use std::collections::HashMap;

pub trait DspProcessor<'a, TSample: audsp::Numeric> {
    fn get_properties(& self) -> & PropStorage<'a, TSample, Self>;
    fn get_mut_properties(&mut self) -> &mut PropStorage<'a, TSample, Self>;
    fn param_changed(&mut self, i32);
    fn sample_rate_changed(&mut self, f32);
    fn get_plugin_name(&self) -> String;
    fn process_stereo_stereo(&mut self, [& [TSample]; 2], [&mut [TSample]; 2]);
}

#[allow(dead_code)]
pub struct PropInfo<'a, TSample: audsp::Numeric, TProcessor: DspProcessor<'a, TSample>> where TSample: 'a {
    id: u32,
    min: TSample,
    max: TSample,
    default: TSample,
    value: TSample,
    norm_value: TSample,
    caption: &'a str,
    measure: &'a str,
    norm: Box<Normalizer<TSample> + 'a>,
    callback : Box<Fn(&mut TProcessor) + 'a>,
}

#[derive(Default)]
pub struct PropStorage<'a, TSample: audsp::Numeric, TProcessor: DspProcessor<'a, TSample>> where TSample: 'a {
    properties: HashMap<u32, PropInfo<'a, TSample, TProcessor>>
}

impl<'a, TSample: audsp::Numeric, TProcessor: DspProcessor<'a, TSample>> PropInfo<'a, TSample, TProcessor> where TSample: 'a {
    pub fn set_from_norm(&mut self, norm: TSample, processor: &mut TProcessor) {
        self.norm_value = norm;
        self.value = self.norm.from_normal(norm);

        let callback = &self.callback;
        callback(processor);
    }

    pub fn get_value(&self) -> TSample {
        return self.value
    }

    pub fn get_norm_value(&self) -> TSample {
        return self.norm_value
    }

    pub fn get_caption(&self) -> String {
        self.caption.to_string()
    }

    pub fn get_measure(&self) -> String {
        self.measure.to_string()
    }
}

impl<'a, TSample: audsp::Numeric, TProcessor> PropStorage<'a, TSample, TProcessor> where TSample: 'a, TProcessor: DspProcessor<'a, TSample> {
    pub fn new() -> Self {
        PropStorage::<TSample, TProcessor>{properties: HashMap::new()}
    }

    pub fn len(&self) -> usize {
        self.properties.len()
    }

    pub fn add_prop<TProv>(&mut self, index: u32, min: TSample, max: TSample, default: TSample, caption: &'a str, measure: &'a str, callback: Box<Fn(&mut TProcessor) + 'a>) where TProv: NormalizerProvider<'a, TSample> {
        let norm = TProv::boxed(min, max);

        self.properties.insert(index, PropInfo::<TSample, TProcessor>{
            id: index,
            min: min,
            max: max,
            default: default,
            value: default,
            norm_value: norm.to_normal(default),
            caption: caption,
            measure: measure,
            norm: norm,
            callback: callback,
            });
    }

    pub fn get_value(&self, i: u32) -> TSample {
        return self.properties.get(&i).map(|x| x.value).unwrap_or(TSample::zero())
    }

    pub fn get_propinfo(&self, index: i32) -> Option<&PropInfo<'a, TSample, TProcessor>> {
        let i:u32 = index as u32;
        self.properties.get(&i)
    }

    pub fn get_mut_propinfo(&mut self, index: i32) -> Option<&mut PropInfo<'a, TSample, TProcessor>> {
        let i:u32 = index as u32;
        self.properties.get_mut(&i)
    }
}
<|endoftext|>