<commit_before>extern crate tokio_core;
extern crate trust_dns_integration;
extern crate trust_dns_proto;
extern crate trust_dns_resolver;
extern crate trust_dns_server;

use std::net::*;
use std::str::FromStr;
use std::sync::{Arc, Mutex};

use tokio_core::reactor::Core;

use trust_dns_proto::op::{NoopMessageFinalizer, Query};
use trust_dns_proto::rr::{Name, RData, RecordType};
use trust_dns_proto::DnsFuture;
use trust_dns_resolver::config::LookupIpStrategy;
use trust_dns_resolver::error::ResolveError;
use trust_dns_resolver::lookup::{InnerLookupFuture, Lookup};
use trust_dns_resolver::lookup_ip::InnerLookupIpFuture;
use trust_dns_resolver::lookup_state::CachingClient;
use trust_dns_resolver::Hosts;
use trust_dns_server::authority::Catalog;

use trust_dns_integration::authority::create_example;
use trust_dns_integration::mock_client::*;
use trust_dns_integration::TestClientStream;

#[test]
fn test_lookup() {
    let authority = create_example();
    let mut catalog = Catalog::new();
    catalog.upsert(authority.origin().clone().into(), authority);

    let mut io_loop = Core::new().unwrap();
    let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
    let client = DnsFuture::new(stream, Box::new(sender), NoopMessageFinalizer::new());

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_lookup_hosts() {
    let authority = create_example();
    let mut catalog = Catalog::new();
    catalog.upsert(authority.origin().clone().into(), authority);

    let mut io_loop = Core::new().unwrap();
    let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
    let client = DnsFuture::new(stream, Box::new(sender), NoopMessageFinalizer::new());

    let mut hosts = Hosts::default();

    hosts.insert(
        Name::from_str("www.example.com.").unwrap(),
        RecordType::A,
        Lookup::new_with_max_ttl(Arc::new(vec![RData::A(Ipv4Addr::new(10, 0, 1, 104))])),
    );

    let lookup = InnerLookupIpFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        LookupIpStrategy::default(),
        CachingClient::new(0, client),
        Default::default(),
        Some(Arc::new(hosts)),
    );
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(lookup.iter().next().unwrap(), Ipv4Addr::new(10, 0, 1, 104));
}

#[test]
fn test_mock_lookup() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let v4_record = v4_record(
        Name::from_str("www.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );
    let message = message(resp_query, vec![v4_record], vec![], vec![]);
    let client = MockClientHandle::<ResolveError>::mock(vec![message.map(Into::into)]);

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );

    let mut io_loop = Core::new().unwrap();
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_cname_lookup() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let cname_record = cname_record(
        Name::from_str("www.example.com.").unwrap(),
        Name::from_str("v4.example.com.").unwrap(),
    );
    let v4_record = v4_record(
        Name::from_str("v4.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );
    let message = message(resp_query, vec![cname_record, v4_record], vec![], vec![]);
    let client = MockClientHandle::mock(vec![message.map(Into::into)]);

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );

    let mut io_loop = Core::new().unwrap();
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_chained_cname_lookup() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let cname_record = cname_record(
        Name::from_str("www.example.com.").unwrap(),
        Name::from_str("v4.example.com.").unwrap(),
    );
    let v4_record = v4_record(
        Name::from_str("v4.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );

    // The first response should be a cname, the second will be the actual record
    let message1 = message(resp_query.clone(), vec![cname_record], vec![], vec![]);
    let message2 = message(resp_query, vec![v4_record], vec![], vec![]);

    // the mock pops messages...
    let client = MockClientHandle::mock(vec![message2.map(Into::into), message1.map(Into::into)]);

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );

    let mut io_loop = Core::new().unwrap();
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_max_chained_lookup_depth() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let cname_record1 = cname_record(
        Name::from_str("www.example.com.").unwrap(),
        Name::from_str("cname2.example.com.").unwrap(),
    );
    let cname_record2 = cname_record(
        Name::from_str("cname2.example.com.").unwrap(),
        Name::from_str("cname3.example.com.").unwrap(),
    );
    let cname_record3 = cname_record(
        Name::from_str("cname3.example.com.").unwrap(),
        Name::from_str("cname4.example.com.").unwrap(),
    );
    let cname_record4 = cname_record(
        Name::from_str("cname4.example.com.").unwrap(),
        Name::from_str("cname5.example.com.").unwrap(),
    );
    let cname_record5 = cname_record(
        Name::from_str("cname5.example.com.").unwrap(),
        Name::from_str("cname6.example.com.").unwrap(),
    );
    let cname_record6 = cname_record(
        Name::from_str("cname6.example.com.").unwrap(),
        Name::from_str("cname7.example.com.").unwrap(),
    );
    let cname_record7 = cname_record(
        Name::from_str("cname7.example.com.").unwrap(),
        Name::from_str("cname8.example.com.").unwrap(),
    );
    let cname_record8 = cname_record(
        Name::from_str("cname8.example.com.").unwrap(),
        Name::from_str("cname9.example.com.").unwrap(),
    );
    let cname_record9 = cname_record(
        Name::from_str("cname9.example.com.").unwrap(),
        Name::from_str("v4.example.com.").unwrap(),
    );
    let v4_record = v4_record(
        Name::from_str("v4.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );

    // The first response should be a cname, the second will be the actual record
    let message1 = message(resp_query.clone(), vec![cname_record1], vec![], vec![]);
    let message2 = message(resp_query.clone(), vec![cname_record2], vec![], vec![]);
    let message3 = message(resp_query.clone(), vec![cname_record3], vec![], vec![]);
    let message4 = message(resp_query.clone(), vec![cname_record4], vec![], vec![]);
    let message5 = message(resp_query.clone(), vec![cname_record5], vec![], vec![]);
    let message6 = message(resp_query.clone(), vec![cname_record6], vec![], vec![]);
    let message7 = message(resp_query.clone(), vec![cname_record7], vec![], vec![]);
    let message8 = message(resp_query.clone(), vec![cname_record8], vec![], vec![]);
    let message9 = message(resp_query.clone(), vec![cname_record9], vec![], vec![]);
    let message10 = message(resp_query, vec![v4_record], vec![], vec![]);

    // the mock pops messages...
    let client = MockClientHandle::mock(vec![
        message10.map(Into::into),
        message9.map(Into::into),
        message8.map(Into::into),
        message7.map(Into::into),
        message6.map(Into::into),
        message5.map(Into::into),
        message4.map(Into::into),
        message3.map(Into::into),
        message2.map(Into::into),
        message1.map(Into::into),
    ]);

    let client = CachingClient::new(0, client);
    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        client.clone(),
    );

    let mut io_loop = Core::new().unwrap();

    println!("performing max cname validation");
    // TODO: validate exact error
    assert!(io_loop.run(lookup).is_err());

    // This query should succeed, as the queue depth should reset to 0 on a failed request
    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("cname9.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        client,
    );

    println!("performing followup resolve, should work");
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}
<commit_msg>fix integration tests<commit_after>extern crate futures;
extern crate tokio_core;
extern crate trust_dns_integration;
extern crate trust_dns_proto;
extern crate trust_dns_resolver;
extern crate trust_dns_server;

use std::net::*;
use std::str::FromStr;
use std::sync::{Arc, Mutex};

use futures::{Future, future};
use tokio_core::reactor::Core;

use trust_dns_proto::op::{NoopMessageFinalizer, Query};
use trust_dns_proto::rr::{Name, RData, RecordType};
use trust_dns_proto::DnsFuture;
use trust_dns_resolver::config::LookupIpStrategy;
use trust_dns_resolver::error::ResolveError;
use trust_dns_resolver::lookup::{InnerLookupFuture, Lookup};
use trust_dns_resolver::lookup_ip::InnerLookupIpFuture;
use trust_dns_resolver::lookup_state::CachingClient;
use trust_dns_resolver::Hosts;
use trust_dns_server::authority::Catalog;

use trust_dns_integration::authority::create_example;
use trust_dns_integration::mock_client::*;
use trust_dns_integration::TestClientStream;

#[test]
fn test_lookup() {
    let authority = create_example();
    let mut catalog = Catalog::new();
    catalog.upsert(authority.origin().clone().into(), authority);

    let mut io_loop = Core::new().unwrap();
    let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
    let client = future::lazy(|| {
        future::ok(DnsFuture::new(stream, Box::new(sender), NoopMessageFinalizer::new()))
    });

    let lookup = client.and_then(|client| {
        InnerLookupFuture::lookup(
            vec![Name::from_str("www.example.com.").unwrap()],
            RecordType::A,
            Default::default(),
            CachingClient::new(0, client),
        )
    });
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_lookup_hosts() {
    let authority = create_example();
    let mut catalog = Catalog::new();
    catalog.upsert(authority.origin().clone().into(), authority);

    let mut io_loop = Core::new().unwrap();
    let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
    let client = future::lazy(|| {
        future::ok(DnsFuture::new(stream, Box::new(sender), NoopMessageFinalizer::new()))
    });

    let mut hosts = Hosts::default();

    hosts.insert(
        Name::from_str("www.example.com.").unwrap(),
        RecordType::A,
        Lookup::new_with_max_ttl(Arc::new(vec![RData::A(Ipv4Addr::new(10, 0, 1, 104))])),
    );

    let lookup = client.and_then(|client| {
        InnerLookupIpFuture::lookup(
            vec![Name::from_str("www.example.com.").unwrap()],
            LookupIpStrategy::default(),
            CachingClient::new(0, client),
            Default::default(),
            Some(Arc::new(hosts)),
        )
    });
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(lookup.iter().next().unwrap(), Ipv4Addr::new(10, 0, 1, 104));
}

#[test]
fn test_mock_lookup() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let v4_record = v4_record(
        Name::from_str("www.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );
    let message = message(resp_query, vec![v4_record], vec![], vec![]);
    let client = MockClientHandle::<ResolveError>::mock(vec![message.map(Into::into)]);

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );

    let mut io_loop = Core::new().unwrap();
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_cname_lookup() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let cname_record = cname_record(
        Name::from_str("www.example.com.").unwrap(),
        Name::from_str("v4.example.com.").unwrap(),
    );
    let v4_record = v4_record(
        Name::from_str("v4.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );
    let message = message(resp_query, vec![cname_record, v4_record], vec![], vec![]);
    let client = MockClientHandle::mock(vec![message.map(Into::into)]);

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );

    let mut io_loop = Core::new().unwrap();
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_chained_cname_lookup() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let cname_record = cname_record(
        Name::from_str("www.example.com.").unwrap(),
        Name::from_str("v4.example.com.").unwrap(),
    );
    let v4_record = v4_record(
        Name::from_str("v4.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );

    // The first response should be a cname, the second will be the actual record
    let message1 = message(resp_query.clone(), vec![cname_record], vec![], vec![]);
    let message2 = message(resp_query, vec![v4_record], vec![], vec![]);

    // the mock pops messages...
    let client = MockClientHandle::mock(vec![message2.map(Into::into), message1.map(Into::into)]);

    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        CachingClient::new(0, client),
    );

    let mut io_loop = Core::new().unwrap();
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}

#[test]
fn test_max_chained_lookup_depth() {
    let resp_query = Query::query(Name::from_str("www.example.com.").unwrap(), RecordType::A);
    let cname_record1 = cname_record(
        Name::from_str("www.example.com.").unwrap(),
        Name::from_str("cname2.example.com.").unwrap(),
    );
    let cname_record2 = cname_record(
        Name::from_str("cname2.example.com.").unwrap(),
        Name::from_str("cname3.example.com.").unwrap(),
    );
    let cname_record3 = cname_record(
        Name::from_str("cname3.example.com.").unwrap(),
        Name::from_str("cname4.example.com.").unwrap(),
    );
    let cname_record4 = cname_record(
        Name::from_str("cname4.example.com.").unwrap(),
        Name::from_str("cname5.example.com.").unwrap(),
    );
    let cname_record5 = cname_record(
        Name::from_str("cname5.example.com.").unwrap(),
        Name::from_str("cname6.example.com.").unwrap(),
    );
    let cname_record6 = cname_record(
        Name::from_str("cname6.example.com.").unwrap(),
        Name::from_str("cname7.example.com.").unwrap(),
    );
    let cname_record7 = cname_record(
        Name::from_str("cname7.example.com.").unwrap(),
        Name::from_str("cname8.example.com.").unwrap(),
    );
    let cname_record8 = cname_record(
        Name::from_str("cname8.example.com.").unwrap(),
        Name::from_str("cname9.example.com.").unwrap(),
    );
    let cname_record9 = cname_record(
        Name::from_str("cname9.example.com.").unwrap(),
        Name::from_str("v4.example.com.").unwrap(),
    );
    let v4_record = v4_record(
        Name::from_str("v4.example.com.").unwrap(),
        Ipv4Addr::new(93, 184, 216, 34),
    );

    // The first response should be a cname, the second will be the actual record
    let message1 = message(resp_query.clone(), vec![cname_record1], vec![], vec![]);
    let message2 = message(resp_query.clone(), vec![cname_record2], vec![], vec![]);
    let message3 = message(resp_query.clone(), vec![cname_record3], vec![], vec![]);
    let message4 = message(resp_query.clone(), vec![cname_record4], vec![], vec![]);
    let message5 = message(resp_query.clone(), vec![cname_record5], vec![], vec![]);
    let message6 = message(resp_query.clone(), vec![cname_record6], vec![], vec![]);
    let message7 = message(resp_query.clone(), vec![cname_record7], vec![], vec![]);
    let message8 = message(resp_query.clone(), vec![cname_record8], vec![], vec![]);
    let message9 = message(resp_query.clone(), vec![cname_record9], vec![], vec![]);
    let message10 = message(resp_query, vec![v4_record], vec![], vec![]);

    // the mock pops messages...
    let client = MockClientHandle::mock(vec![
        message10.map(Into::into),
        message9.map(Into::into),
        message8.map(Into::into),
        message7.map(Into::into),
        message6.map(Into::into),
        message5.map(Into::into),
        message4.map(Into::into),
        message3.map(Into::into),
        message2.map(Into::into),
        message1.map(Into::into),
    ]);

    let client = CachingClient::new(0, client);
    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("www.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        client.clone(),
    );

    let mut io_loop = Core::new().unwrap();

    println!("performing max cname validation");
    // TODO: validate exact error
    assert!(io_loop.run(lookup).is_err());

    // This query should succeed, as the queue depth should reset to 0 on a failed request
    let lookup = InnerLookupFuture::lookup(
        vec![Name::from_str("cname9.example.com.").unwrap()],
        RecordType::A,
        Default::default(),
        client,
    );

    println!("performing followup resolve, should work");
    let lookup = io_loop.run(lookup).unwrap();

    assert_eq!(
        *lookup.iter().next().unwrap(),
        RData::A(Ipv4Addr::new(93, 184, 216, 34))
    );
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
#[cfg(not(any(feature = "test", test)))]
use std::{env, thread, process};

use query::{Query, Response};
#[cfg(not(any(feature = "test", test)))]
use messenger;

/// Manages the renderer process and all communication with it
#[cfg(not(any(feature = "test", test)))]
pub struct RendererProcess {
    process: process::Child,
    thread_handle: Option<thread::JoinHandle<()>>,
    /// Channel for receiving responses from the rendering process
    response_channel: mpsc::Receiver<Response>,
}

#[cfg(not(any(feature = "test", test)))]
impl RendererProcess {
    /// Spawn the renderer process and also a thread for communicating with that process
    pub fn new() -> Self {
        let current_exe = env::current_exe()
            .expect("Could not read path of the currently running executable")
            .into_os_string();
        let mut renderer_process = process::Command::new(current_exe)
            .env("RUN_TURTLE_CANVAS", "true")
            .stdin(process::Stdio::piped())
            .stdout(process::Stdio::piped())
            .stderr(process::Stdio::inherit())
            .spawn()
            .expect("renderer process failed to start");

        let renderer_stdout = renderer_process.stdout.take()
            .expect("renderer process was not opened with stdout");
        let (response_tx, response_rx) = mpsc::channel();
        let handle = thread::spawn(move || {
            // Continously read responses from the renderer process
            // This is in its own thread because it uses blocking IO and we don't want to block
            // the main thread waiting for the renderer process
            messenger::read_forever(
                renderer_stdout,
                "bug: unable to read data from renderer process",
                "bug: failed to read response from renderer process",
                |resp| response_tx.send(resp).map_err(|_| ()),
            );
        });

        Self {
            process: renderer_process,
            thread_handle: Some(handle),
            response_channel: response_rx,
        }
    }

    /// Sends a query and automatically decides whether or not to wait for a response.
    ///
    /// If a query does not require a response, this function will return immediately after
    /// sending the query
    pub fn send_query(&mut self, query: Query) -> Option<Response> {
        messenger::send(
            match self.process.stdin {
                Some(ref mut stdin) => stdin,
                None => unreachable!("bug: renderer process was not opened with stdin"),
            },
            &query,
            "bug: unable to write final newline when sending query"
        ).unwrap_or_else(|_| {
            // Something went wrong while sending the query, check if the renderer process
            // panicked (exited with an error)
            match self.process.try_wait() {
                Ok(Some(status)) => {
                    if status.success() {
                        // The window/renderer process was closed normally
                        process::exit(0);
                    }
                    else {
                        // Something went wrong, likely the other thread panicked
                        process::exit(1);
                    }
                },
                Ok(None) => panic!("bug: failed to send query even though renderer process was still running"),
                Err(_) => panic!("bug: unable to check the exit status of the renderer process"),
            }
        });

        // Requests need responses
        if let Query::Request(_) = query {
            Some(self.wait_for_response())
        }
        else {
            None
        }
    }

    fn wait_for_response(&mut self) -> Response {
        self.response_channel.recv().unwrap_or_else(|_| {
            // The client thread has exited, that means that the renderer process has exited
            // and the window has closed
            self.exit_process()
        })
    }

    /// Exits the current process with the correct error code
    ///
    /// Panics if the thread handle has already been consumed
    #[inline]
    fn exit_process(&mut self) -> ! {
        let status = self.thread_handle.take().ok_or_else(|| {
            unreachable!("bug: the thread handle was used but the process did not end");
        }).and_then(|handle| {
            // First check if the other thread panicked before it quit
            handle.join().map_err(|_| ())
        }).and_then(|_| {
            // Then check if the renderer process ended normally
            self.process.wait()
                .map_err(|_| unreachable!("bug: renderer process never ran even though we exited"))
                .and_then(|status| if status.success() { Ok(()) } else { Err(()) })
        });

        match status {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(1),
        }
    }
}

#[cfg(not(any(feature = "test", test)))]
impl Drop for RendererProcess {
    fn drop(&mut self) {
        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            process::exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        if let Some(handle) = self.thread_handle.take() {
            handle.join().unwrap_or_else(|_| {
                // If this returns an error, the other thread panicked
                process::exit(1);
            });
        }

        // Now that the thread has completed, the process likely has as well (or is about to).
        // Check its exit status to see if we need to quit with an error
        match self.process.wait() {
            Ok(status) => if !status.success() {
                process::exit(1);
            },
            Err(_) => unreachable!("bug: renderer process never ran even though we exited"),
        }
    }
}

/// A special "renderer process" specifically for tests. Simulates the renderer process by
/// providing all of the same functionality and reusing internal parts of the
#[cfg(any(feature = "test", test))]
pub struct RendererProcess {
    app: ::app::TurtleApp,
    events: (mpsc::Sender<::Event>, mpsc::Receiver<::Event>),
    drawing: (mpsc::Sender<::query::DrawingCommand>, mpsc::Receiver<::query::DrawingCommand>),
}

#[cfg(any(feature = "test", test))]
impl RendererProcess {
    pub fn new() -> Self {
        Self {
            app: ::app::TurtleApp::new(),
            events: mpsc::channel(),
            drawing: mpsc::channel(),
        }
    }

    pub fn send_query(&mut self, query: Query) -> Option<Response> {
        ::server::handle_query_for_test_use_only(query, &mut self.app, &self.events.1, &self.drawing.0)
            .expect("test bug: a query failed to be successful")
    }
}
<commit_msg>Filled in missing part of a documentation comment<commit_after>use std::sync::mpsc;
#[cfg(not(any(feature = "test", test)))]
use std::{env, thread, process};

use query::{Query, Response};
#[cfg(not(any(feature = "test", test)))]
use messenger;

/// Manages the renderer process and all communication with it
#[cfg(not(any(feature = "test", test)))]
pub struct RendererProcess {
    process: process::Child,
    thread_handle: Option<thread::JoinHandle<()>>,
    /// Channel for receiving responses from the rendering process
    response_channel: mpsc::Receiver<Response>,
}

#[cfg(not(any(feature = "test", test)))]
impl RendererProcess {
    /// Spawn the renderer process and also a thread for communicating with that process
    pub fn new() -> Self {
        let current_exe = env::current_exe()
            .expect("Could not read path of the currently running executable")
            .into_os_string();
        let mut renderer_process = process::Command::new(current_exe)
            .env("RUN_TURTLE_CANVAS", "true")
            .stdin(process::Stdio::piped())
            .stdout(process::Stdio::piped())
            .stderr(process::Stdio::inherit())
            .spawn()
            .expect("renderer process failed to start");

        let renderer_stdout = renderer_process.stdout.take()
            .expect("renderer process was not opened with stdout");
        let (response_tx, response_rx) = mpsc::channel();
        let handle = thread::spawn(move || {
            // Continously read responses from the renderer process
            // This is in its own thread because it uses blocking IO and we don't want to block
            // the main thread waiting for the renderer process
            messenger::read_forever(
                renderer_stdout,
                "bug: unable to read data from renderer process",
                "bug: failed to read response from renderer process",
                |resp| response_tx.send(resp).map_err(|_| ()),
            );
        });

        Self {
            process: renderer_process,
            thread_handle: Some(handle),
            response_channel: response_rx,
        }
    }

    /// Sends a query and automatically decides whether or not to wait for a response.
    ///
    /// If a query does not require a response, this function will return immediately after
    /// sending the query
    pub fn send_query(&mut self, query: Query) -> Option<Response> {
        messenger::send(
            match self.process.stdin {
                Some(ref mut stdin) => stdin,
                None => unreachable!("bug: renderer process was not opened with stdin"),
            },
            &query,
            "bug: unable to write final newline when sending query"
        ).unwrap_or_else(|_| {
            // Something went wrong while sending the query, check if the renderer process
            // panicked (exited with an error)
            match self.process.try_wait() {
                Ok(Some(status)) => {
                    if status.success() {
                        // The window/renderer process was closed normally
                        process::exit(0);
                    }
                    else {
                        // Something went wrong, likely the other thread panicked
                        process::exit(1);
                    }
                },
                Ok(None) => panic!("bug: failed to send query even though renderer process was still running"),
                Err(_) => panic!("bug: unable to check the exit status of the renderer process"),
            }
        });

        // Requests need responses
        if let Query::Request(_) = query {
            Some(self.wait_for_response())
        }
        else {
            None
        }
    }

    fn wait_for_response(&mut self) -> Response {
        self.response_channel.recv().unwrap_or_else(|_| {
            // The client thread has exited, that means that the renderer process has exited
            // and the window has closed
            self.exit_process()
        })
    }

    /// Exits the current process with the correct error code
    ///
    /// Panics if the thread handle has already been consumed
    #[inline]
    fn exit_process(&mut self) -> ! {
        let status = self.thread_handle.take().ok_or_else(|| {
            unreachable!("bug: the thread handle was used but the process did not end");
        }).and_then(|handle| {
            // First check if the other thread panicked before it quit
            handle.join().map_err(|_| ())
        }).and_then(|_| {
            // Then check if the renderer process ended normally
            self.process.wait()
                .map_err(|_| unreachable!("bug: renderer process never ran even though we exited"))
                .and_then(|status| if status.success() { Ok(()) } else { Err(()) })
        });

        match status {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(1),
        }
    }
}

#[cfg(not(any(feature = "test", test)))]
impl Drop for RendererProcess {
    fn drop(&mut self) {
        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            process::exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        if let Some(handle) = self.thread_handle.take() {
            handle.join().unwrap_or_else(|_| {
                // If this returns an error, the other thread panicked
                process::exit(1);
            });
        }

        // Now that the thread has completed, the process likely has as well (or is about to).
        // Check its exit status to see if we need to quit with an error
        match self.process.wait() {
            Ok(status) => if !status.success() {
                process::exit(1);
            },
            Err(_) => unreachable!("bug: renderer process never ran even though we exited"),
        }
    }
}

/// A special "renderer process" specifically for tests. Simulates the renderer process by
/// providing all of the same functionality and reusing internal parts of the server. No actual
/// process or additional threads are spawned.
#[cfg(any(feature = "test", test))]
pub struct RendererProcess {
    app: ::app::TurtleApp,
    events: (mpsc::Sender<::Event>, mpsc::Receiver<::Event>),
    drawing: (mpsc::Sender<::query::DrawingCommand>, mpsc::Receiver<::query::DrawingCommand>),
}

#[cfg(any(feature = "test", test))]
impl RendererProcess {
    pub fn new() -> Self {
        Self {
            app: ::app::TurtleApp::new(),
            events: mpsc::channel(),
            drawing: mpsc::channel(),
        }
    }

    pub fn send_query(&mut self, query: Query) -> Option<Response> {
        ::server::handle_query_for_test_use_only(query, &mut self.app, &self.events.1, &self.drawing.0)
            .expect("test bug: a query failed to be successful")
    }
}
<|endoftext|>


<commit_before>use libc::{c_char, int32_t};
use std;
use std::ffi::CString;
use std::error::Error;

use backend::Backend;
use provider::error;
use provider::Output;
use provider::service::ServiceProvider;

pub struct Service<'a> {
    name: &'static str,
    backend: &'a Backend,
    provider: &'a ServiceProvider,
    error: Option<error::Error>,
}

impl<'a> Service<'a> {
    pub fn new(n: &'static str, b: &'a Backend, p: &'a ServiceProvider) -> Service<'a> {
        Service {
            name: n,
            backend: b,
            provider: p,
            error: None,
        }
    }

    pub fn is_running(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.is_running(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_enabled(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.is_enabled(self.name))
            .and_then(Output::to_bool)
    }

    pub fn enable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.enable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn disable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.disable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn start(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.start(self.name))
            .and_then(Output::to_bool)
    }

    pub fn stop(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.stop(self.name))
            .and_then(Output::to_bool)
    }

    pub fn reload(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.reload(self.name))
            .and_then(Output::to_bool)
    }

    pub fn restart(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.restart(self.name))
            .and_then(Output::to_bool)
    }
}

// Wrapper functions for FFI

#[no_mangle]
pub extern "C" fn resource_service_free(ptr: *mut Service) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn resource_service_error_description(ptr: *const Service) -> *const c_char {
    let s = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    match s.error {
        Some(ref e) => CString::new(e.description()).unwrap().into_raw(),
        None => std::ptr::null(),
    }
}

#[no_mangle]
pub extern "C" fn resource_service_is_running(ptr: *mut Service) -> int32_t {
    let s = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };

    match s.is_running() {
        Ok(f) => if f { 1 } else { 0 },
        Err(e) => {
            s.error = Some(e);
            return -1;
        }
    }
}

#[no_mangle]
pub extern "C" fn resource_service_is_enabled(ptr: *mut Service) -> int32_t {
    let s = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };

    match s.is_enabled() {
        Ok(f) => if f { 1 } else { 0 },
        Err(e) => {
            s.error = Some(e);
            return -1;
        }
    }
}
<commit_msg>Add a wrapper funcion for service.enable()<commit_after>use libc::{c_char, int32_t};
use std;
use std::ffi::CString;
use std::error::Error;

use backend::Backend;
use provider::error;
use provider::Output;
use provider::service::ServiceProvider;

pub struct Service<'a> {
    name: &'static str,
    backend: &'a Backend,
    provider: &'a ServiceProvider,
    error: Option<error::Error>,
}

impl<'a> Service<'a> {
    pub fn new(n: &'static str, b: &'a Backend, p: &'a ServiceProvider) -> Service<'a> {
        Service {
            name: n,
            backend: b,
            provider: p,
            error: None,
        }
    }

    pub fn is_running(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.is_running(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_enabled(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.is_enabled(self.name))
            .and_then(Output::to_bool)
    }

    pub fn enable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.enable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn disable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.disable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn start(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.start(self.name))
            .and_then(Output::to_bool)
    }

    pub fn stop(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.stop(self.name))
            .and_then(Output::to_bool)
    }

    pub fn reload(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.reload(self.name))
            .and_then(Output::to_bool)
    }

    pub fn restart(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.restart(self.name))
            .and_then(Output::to_bool)
    }
}

// Wrapper functions for FFI

#[no_mangle]
pub extern "C" fn resource_service_free(ptr: *mut Service) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn resource_service_error_description(ptr: *const Service) -> *const c_char {
    let s = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    match s.error {
        Some(ref e) => CString::new(e.description()).unwrap().into_raw(),
        None => std::ptr::null(),
    }
}

#[no_mangle]
pub extern "C" fn resource_service_is_running(ptr: *mut Service) -> int32_t {
    let s = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };

    match s.is_running() {
        Ok(f) => if f { 1 } else { 0 },
        Err(e) => {
            s.error = Some(e);
            return -1;
        }
    }
}

#[no_mangle]
pub extern "C" fn resource_service_is_enabled(ptr: *mut Service) -> int32_t {
    let s = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };

    match s.is_enabled() {
        Ok(f) => if f { 1 } else { 0 },
        Err(e) => {
            s.error = Some(e);
            return -1;
        }
    }
}

#[no_mangle]
pub extern "C" fn resource_service_enable(ptr: *mut Service) -> int32_t {
    let s = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };

    match s.enable() {
        Ok(f) => if f { 1 } else { 0 },
        Err(e) => {
            s.error = Some(e);
            return -1;
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate vst2;

use vst2::buffer::AudioBuffer;
use vst2::plugin::{Category, Plugin, Info, CanDo};
use vst2::event::Event;
use vst2::api::{Supported, Events};

use std::f64::consts::PI;

/// Convert the midi note's pitch into the equivalent frequency.
///
/// This function assumes A4 is 440hz.
fn midi_pitch_to_freq(pitch: u8) -> f64 {
    const A4_PITCH: u8 = 69;
    const A4_FREQ: f64 = 440.0;

    (((pitch - A4_PITCH) as f64) / 12.).exp2() * A4_FREQ
}

struct SineSynth {
    sample_rate: f64,
    time: f64,
    note_duration: f64,
    note: Option<u8>,
}

impl SineSynth {
    fn time_per_sample(&self) -> f64 {
        1.0 / self.sample_rate
    }

    /// Process an incoming midi event.
    ///
    /// The midi data is split up like so:
    ///
    /// `data[0]`: Contains the status and the channel. Source: [source]
    /// `data[1]`: Contains the supplemental data for the message - so, if this was a NoteOn then
    ///            this would contain the note.
    /// `data[2]`: Further supplemental data. Would be velocity in the case of a NoteOn message.
    ///
    /// [source]: http://www.midimountain.com/midi/midi_status.htm
    fn process_midi_event(&mut self, data: [u8; 3]) {
        match data[0] {
            128 => self.note_off(data[1]),
            144 => self.note_on(data[1]),
            _ => ()
        }
    }

    fn note_on(&mut self, note: u8) {
        self.note_duration = 0.0;
        self.note = Some(note)
    }

    fn note_off(&mut self, note: u8) {
        if self.note == Some(note) {
            self.note = None
        }
    }
}

pub const TAU : f64 = PI * 2.0;

impl Default for SineSynth {
    fn default() -> SineSynth {
        SineSynth {
            sample_rate: 44100.0,
            note_duration: 0.0,
            time: 0.0,
            note: None,
        }
    }
}

impl Plugin for SineSynth {
    fn get_info(&self) -> Info {
        Info {
            name: "SineSynth".to_string(),
            vendor: "DeathDisco".to_string(),
            unique_id: 6667,
            category: Category::Synth,
            inputs: 2,
            outputs: 2,
            parameters: 0,
            initial_delay: 0,
            ..Info::default()
        }
    }

    #[allow(unused_variables)]
    fn process_events(&mut self, events: &Events) {
        for event in events.events() {
            match event {
                Event::Midi { data, ..  } => self.process_midi_event(data),
                // More events can be handled here.
                _ => {}
            }
        }
    }

    fn set_sample_rate(&mut self, rate: f32) {
        self.sample_rate = rate as f64;
    }

    fn process(&mut self, buffer: &mut AudioBuffer<f32>) {
        let samples = buffer.samples();

        let per_sample = self.time_per_sample();

        for (input_buffer, output_buffer) in buffer.zip() {
            let mut t = self.time;

            for (_, output_sample) in input_buffer.iter().zip(output_buffer) {
                if let Some(current_note) = self.note {
                    let signal = (t * midi_pitch_to_freq(current_note) * TAU).sin();

                    // Apply a quick envelope to the attack of the signal to avoid popping.
                    let attack = 0.5;
                    let alpha = if self.note_duration < attack {
                        self.note_duration / attack
                    } else {
                        1.0
                    };

                    *output_sample = (signal * alpha) as f32;

                    t += per_sample;
                } else {
                    *output_sample = 0.0;
                }
            }
        }

        self.time += samples as f64 * per_sample;
        self.note_duration += samples as f64 * per_sample;
    }

    fn can_do(&self, can_do: CanDo) -> Supported {
        match can_do {
            CanDo::ReceiveMidiEvent => Supported::Yes,
            _ => Supported::Maybe
        }
    }
}

plugin_main!(SineSynth);
<commit_msg>made sine_synth example work on stable<commit_after>#[macro_use] extern crate vst2;

use vst2::buffer::AudioBuffer;
use vst2::plugin::{Category, Plugin, Info, CanDo};
use vst2::event::Event;
use vst2::api::{Supported, Events};

use std::f64::consts::PI;

/// Convert the midi note's pitch into the equivalent frequency.
///
/// This function assumes A4 is 440hz.
fn midi_pitch_to_freq(pitch: u8) -> f64 {
    const A4_PITCH: u8 = 69;
    const A4_FREQ: f64 = 440.0;

    (((pitch - A4_PITCH) as f64) / 12.).exp2() * A4_FREQ
}

struct SineSynth {
    sample_rate: f64,
    time: f64,
    note_duration: f64,
    note: Option<u8>,
}

impl SineSynth {
    fn time_per_sample(&self) -> f64 {
        1.0 / self.sample_rate
    }

    /// Process an incoming midi event.
    ///
    /// The midi data is split up like so:
    ///
    /// `data[0]`: Contains the status and the channel. Source: [source]
    /// `data[1]`: Contains the supplemental data for the message - so, if this was a NoteOn then
    ///            this would contain the note.
    /// `data[2]`: Further supplemental data. Would be velocity in the case of a NoteOn message.
    ///
    /// [source]: http://www.midimountain.com/midi/midi_status.htm
    fn process_midi_event(&mut self, data: [u8; 3]) {
        match data[0] {
            128 => self.note_off(data[1]),
            144 => self.note_on(data[1]),
            _ => ()
        }
    }

    fn note_on(&mut self, note: u8) {
        self.note_duration = 0.0;
        self.note = Some(note)
    }

    fn note_off(&mut self, note: u8) {
        if self.note == Some(note) {
            self.note = None
        }
    }
}

pub const TAU : f64 = PI * 2.0;

impl Default for SineSynth {
    fn default() -> SineSynth {
        SineSynth {
            sample_rate: 44100.0,
            note_duration: 0.0,
            time: 0.0,
            note: None,
        }
    }
}

impl Plugin for SineSynth {
    fn get_info(&self) -> Info {
        Info {
            name: "SineSynth".to_string(),
            vendor: "DeathDisco".to_string(),
            unique_id: 6667,
            category: Category::Synth,
            inputs: 2,
            outputs: 2,
            parameters: 0,
            initial_delay: 0,
            ..Info::default()
        }
    }

    #[allow(unused_variables)]
    fn process_events(&mut self, events: &Events) {
        for &e in events.events_raw() {
            let event: Event = Event::from(unsafe { *e });
            match event {
                Event::Midi { data, .. } => self.process_midi_event(data),
                // More events can be handled here.
                _ => ()
            }
        }
        /* on nightly you can just enable the "nightly" feature and then do:
        for event in events.events() {
            match event {
                Event::Midi { data, ..  } => self.process_midi_event(data),
                // More events can be handled here.
                _ => {}
            }
        }
        */
    }

    fn set_sample_rate(&mut self, rate: f32) {
        self.sample_rate = rate as f64;
    }

    fn process(&mut self, buffer: &mut AudioBuffer<f32>) {
        let samples = buffer.samples();

        let per_sample = self.time_per_sample();

        for (input_buffer, output_buffer) in buffer.zip() {
            let mut t = self.time;

            for (_, output_sample) in input_buffer.iter().zip(output_buffer) {
                if let Some(current_note) = self.note {
                    let signal = (t * midi_pitch_to_freq(current_note) * TAU).sin();

                    // Apply a quick envelope to the attack of the signal to avoid popping.
                    let attack = 0.5;
                    let alpha = if self.note_duration < attack {
                        self.note_duration / attack
                    } else {
                        1.0
                    };

                    *output_sample = (signal * alpha) as f32;

                    t += per_sample;
                } else {
                    *output_sample = 0.0;
                }
            }
        }

        self.time += samples as f64 * per_sample;
        self.note_duration += samples as f64 * per_sample;
    }

    fn can_do(&self, can_do: CanDo) -> Supported {
        match can_do {
            CanDo::ReceiveMidiEvent => Supported::Yes,
            _ => Supported::Maybe
        }
    }
}

plugin_main!(SineSynth);
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate examples;
extern crate cgmath;
extern crate winit;
extern crate time;

#[macro_use]
extern crate vulkano;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;
use vulkano::command_buffer::CommandBufferBuilder;
use vulkano::sync::GpuFuture;
use vulkano::image::ImageView;

use std::sync::Arc;

mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_vs.glsl")} }
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_fs.glsl")} }

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    let extensions = vulkano_win::required_extensions();
    let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let window = winit::WindowBuilder::new().build_vk_surface(&instance).unwrap();

    let queue = physical.queue_families().find(|q| q.supports_graphics() &&
                                                   window.surface().is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
        .. vulkano::device::DeviceExtensions::none()
    };

    let (device, mut queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
                                                            &device_ext, [(queue, 0.5)].iter().cloned())
                               .expect("failed to create device");
    let queue = queues.next().unwrap();

    let (swapchain, images) = {
        let caps = window.surface().get_capabilities(&physical).expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
        let present = caps.present_modes.iter().next().unwrap();
        let usage = caps.supported_usage_flags;
        let format = caps.supported_formats[0].0;

        vulkano::swapchain::Swapchain::new(&device, &window.surface(), caps.min_image_count, format, dimensions, 1,
                                           &usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           vulkano::swapchain::CompositeAlpha::Opaque,
                                           present, true, None).expect("failed to create swapchain")
    };

    let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(&device, images[0].dimensions(), vulkano::format::D16Unorm).unwrap().into_image_view();

    let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
                                .expect("failed to create buffer");

    let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::NORMALS.iter().cloned())
                                .expect("failed to create buffer");

    let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::INDICES.iter().cloned())
                                .expect("failed to create buffer");

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<vs::ty::Data>
                               ::from_data(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()),
                                vs::ty::Data {
                                    world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
                                    view : (view * scale).into(),
                                    proj : proj.into(),
                                })
                               .expect("failed to create buffer");

    let vs = vs::Shader::load(&device).expect("failed to create shader module");
    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    let renderpass = Arc::new(
        single_pass_renderpass!(device.clone(),
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: images[0].format(),
                    samples: 1,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: vulkano::image::ImageAccess::format(&depth_buffer),
                    samples: 1,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        ).unwrap()
    );

    let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::GraphicsPipelineParams {
        vertex_input: vulkano::pipeline::vertex::TwoBuffersDefinition::new(),
        vertex_shader: vs.main_entry_point(),
        input_assembly: vulkano::pipeline::input_assembly::InputAssembly::triangle_list(),
        tessellation: None,
        geometry_shader: None,
        viewport: vulkano::pipeline::viewport::ViewportsState::Fixed {
            data: vec![(
                vulkano::pipeline::viewport::Viewport {
                    origin: [0.0, 0.0],
                    depth_range: 0.0 .. 1.0,
                    dimensions: [images[0].dimensions()[0] as f32, images[0].dimensions()[1] as f32],
                },
                vulkano::pipeline::viewport::Scissor::irrelevant()
            )],
        },
        raster: Default::default(),
        multisample: vulkano::pipeline::multisample::Multisample::disabled(),
        fragment_shader: fs.main_entry_point(),
        depth_stencil: vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test(),
        blend: vulkano::pipeline::blend::Blend::pass_through(),
        render_pass: vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap(),
    }).unwrap());

    let set = Arc::new(simple_descriptor_set!(pipeline.clone(), 0, {
        uniforms: uniform_buffer.clone()
    }));

    let framebuffers = images.iter().map(|image| {
        let attachments = renderpass.desc().start_attachments()
            .color(image.clone()).depth(depth_buffer.clone());
        let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];

        vulkano::framebuffer::Framebuffer::new(renderpass.clone(), dimensions, attachments).unwrap()
    }).collect::<Vec<_>>();

    let mut submissions: Vec<Box<GpuFuture>> = Vec::new();

    loop {
        while submissions.len() >= 4 {
            submissions.remove(0);
        }

        {
            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write().unwrap();

            let rotation = cgmath::Matrix3::from_angle_y(cgmath::Rad(time::precise_time_ns() as f32 * 0.000000001));

            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.world = cgmath::Matrix4::from(rotation).into();
        }

        let (image_num, future) = swapchain.acquire_next_image(std::time::Duration::new(1, 0)).unwrap();

        let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
            .begin_render_pass(
                framebuffers[image_num].clone(), false,
                renderpass.desc().start_clear_values()
                    .color([0.0, 0.0, 1.0, 1.0]).depth((1f32)))
            .draw_indexed(
                pipeline.clone(), vulkano::command_buffer::DynamicState::none(),
                (vertex_buffer.clone(), normals_buffer.clone()),
                index_buffer.clone(), set.clone(), ())
            .end_render_pass()
            .build().unwrap();

        let future = future
            .then_execute(queue.clone(), command_buffer)
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence();
        future.flush().unwrap();
        submissions.push(Box::new(future) as Box<_>);

        for ev in window.window().poll_events() {
            match ev {
                winit::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Fix example<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate examples;
extern crate cgmath;
extern crate winit;
extern crate time;

#[macro_use]
extern crate vulkano;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;
use vulkano::command_buffer::CommandBufferBuilder;
use vulkano::sync::GpuFuture;
use vulkano::image::ImageView;

use std::sync::Arc;

mod vs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_vs.glsl")} }
mod fs { include!{concat!(env!("OUT_DIR"), "/shaders/src/bin/teapot_fs.glsl")} }

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    let extensions = vulkano_win::required_extensions();
    let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let window = winit::WindowBuilder::new().build_vk_surface(&instance).unwrap();

    let queue = physical.queue_families().find(|q| q.supports_graphics() &&
                                                   window.surface().is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
        .. vulkano::device::DeviceExtensions::none()
    };

    let (device, mut queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
                                                            &device_ext, [(queue, 0.5)].iter().cloned())
                               .expect("failed to create device");
    let queue = queues.next().unwrap();

    let (swapchain, images) = {
        let caps = window.surface().get_capabilities(&physical).expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
        let present = caps.present_modes.iter().next().unwrap();
        let usage = caps.supported_usage_flags;
        let format = caps.supported_formats[0].0;

        vulkano::swapchain::Swapchain::new(&device, &window.surface(), caps.min_image_count, format, dimensions, 1,
                                           &usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           vulkano::swapchain::CompositeAlpha::Opaque,
                                           present, true, None).expect("failed to create swapchain")
    };

    let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(&device, images[0].dimensions(), vulkano::format::D16Unorm).unwrap().access();

    let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
                                .expect("failed to create buffer");

    let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::NORMALS.iter().cloned())
                                .expect("failed to create buffer");

    let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::INDICES.iter().cloned())
                                .expect("failed to create buffer");

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { let d = images[0].dimensions(); d[0] as f32 / d[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<vs::ty::Data>
                               ::from_data(&device, &vulkano::buffer::BufferUsage::all(), Some(queue.family()),
                                vs::ty::Data {
                                    world : <cgmath::Matrix4<f32> as cgmath::SquareMatrix>::identity().into(),
                                    view : (view * scale).into(),
                                    proj : proj.into(),
                                })
                               .expect("failed to create buffer");

    let vs = vs::Shader::load(&device).expect("failed to create shader module");
    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    let renderpass = Arc::new(
        single_pass_renderpass!(device.clone(),
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: images[0].format(),
                    samples: 1,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: vulkano::image::ImageAccess::format(&depth_buffer),
                    samples: 1,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        ).unwrap()
    );

    let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::new(&device, vulkano::pipeline::GraphicsPipelineParams {
        vertex_input: vulkano::pipeline::vertex::TwoBuffersDefinition::new(),
        vertex_shader: vs.main_entry_point(),
        input_assembly: vulkano::pipeline::input_assembly::InputAssembly::triangle_list(),
        tessellation: None,
        geometry_shader: None,
        viewport: vulkano::pipeline::viewport::ViewportsState::Fixed {
            data: vec![(
                vulkano::pipeline::viewport::Viewport {
                    origin: [0.0, 0.0],
                    depth_range: 0.0 .. 1.0,
                    dimensions: [images[0].dimensions()[0] as f32, images[0].dimensions()[1] as f32],
                },
                vulkano::pipeline::viewport::Scissor::irrelevant()
            )],
        },
        raster: Default::default(),
        multisample: vulkano::pipeline::multisample::Multisample::disabled(),
        fragment_shader: fs.main_entry_point(),
        depth_stencil: vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test(),
        blend: vulkano::pipeline::blend::Blend::pass_through(),
        render_pass: vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap(),
    }).unwrap());

    let set = Arc::new(simple_descriptor_set!(pipeline.clone(), 0, {
        uniforms: uniform_buffer.clone()
    }));

    let framebuffers = images.iter().map(|image| {
        let attachments = renderpass.desc().start_attachments()
            .color(image.clone()).depth(depth_buffer.clone());
        let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];

        vulkano::framebuffer::Framebuffer::new(renderpass.clone(), dimensions, attachments).unwrap()
    }).collect::<Vec<_>>();

    let mut submissions: Vec<Box<GpuFuture>> = Vec::new();

    loop {
        while submissions.len() >= 4 {
            submissions.remove(0);
        }

        {
            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write().unwrap();

            let rotation = cgmath::Matrix3::from_angle_y(cgmath::Rad(time::precise_time_ns() as f32 * 0.000000001));

            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.world = cgmath::Matrix4::from(rotation).into();
        }

        let (image_num, future) = swapchain.acquire_next_image(std::time::Duration::new(1, 0)).unwrap();

        let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
            .begin_render_pass(
                framebuffers[image_num].clone(), false,
                renderpass.desc().start_clear_values()
                    .color([0.0, 0.0, 1.0, 1.0]).depth((1f32)))
            .draw_indexed(
                pipeline.clone(), vulkano::command_buffer::DynamicState::none(),
                (vertex_buffer.clone(), normals_buffer.clone()),
                index_buffer.clone(), set.clone(), ())
            .end_render_pass()
            .build().unwrap();

        let future = future
            .then_execute(queue.clone(), command_buffer)
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence();
        future.flush().unwrap();
        submissions.push(Box::new(future) as Box<_>);

        for ev in window.window().poll_events() {
            match ev {
                winit::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>