<commit_before>extern crate portaudio;

static SECONDS: usize = 1;

fn main()
{
    portaudio::initialize().unwrap();
    print_devs();
    println!("{:?}", demo());
    portaudio::terminate().unwrap();
}

fn print_devs()
{
    for i in (0 .. portaudio::device::get_count().unwrap())
    {
        match portaudio::device::get_info(i)
        {
            None => {},
            Some(info) => println!("{}: {}", i, info.name),
        }
    }
}

fn demo() -> portaudio::PaResult
{
    let stream = try!(portaudio::stream::Stream::open_default(1, 1, 44100.0, portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED, None));

    try!(stream.start());

    let input = try!(stream.read(44100));

    let mut phase = 0.0f32;
    let mut buffer = Vec::with_capacity(44100 * SECONDS);
    for _i in (0 .. 44100 * SECONDS)
    {
        buffer.push(phase);

        phase += 0.007;
        if phase > 1.0 { phase -= 2.0; }
    }

    let waiter = std::thread::scoped(|| {
        std::thread::sleep_ms((SECONDS * 1000) as u32);
    });

    match stream.write(&*buffer)
    {
        Err(e) => { println!("write 1: Err({:?})", e); },
        Ok(()) => {},
    }

    match stream.write(&*input)
    {
        Err(e) => { println!("write 2: Err({:?})", e); },
        Ok(()) => {},
    }

    let _ = waiter.join();

    Ok(())
}
<commit_msg>Use a barrier instead of thread::scoped<commit_after>extern crate portaudio;

static SECONDS: usize = 1;

fn main()
{
    portaudio::initialize().unwrap();
    print_devs();
    println!("{:?}", demo());
    portaudio::terminate().unwrap();
}

fn print_devs()
{
    for i in (0 .. portaudio::device::get_count().unwrap())
    {
        match portaudio::device::get_info(i)
        {
            None => {},
            Some(info) => println!("{}: {}", i, info.name),
        }
    }
}

fn demo() -> portaudio::PaResult
{
    let stream = try!(portaudio::stream::Stream::open_default(1, 1, 44100.0, portaudio::stream::FRAMES_PER_BUFFER_UNSPECIFIED, None));

    try!(stream.start());

    let input = try!(stream.read(44100));

    let mut phase = 0.0f32;
    let mut buffer = Vec::with_capacity(44100 * SECONDS);
    for _i in (0 .. 44100 * SECONDS)
    {
        buffer.push(phase);

        phase += 0.007;
        if phase > 1.0 { phase -= 2.0; }
    }

    let barrier = std::sync::Arc::new(std::sync::Barrier::new(2));
    let sleep = barrier.clone();
    std::thread::spawn(move|| {
        std::thread::sleep_ms((SECONDS * 1000) as u32);
        barrier.wait();
    });

    match stream.write(&*buffer)
    {
        Err(e) => { println!("write 1: Err({:?})", e); },
        Ok(()) => {},
    }

    match stream.write(&*input)
    {
        Err(e) => { println!("write 2: Err({:?})", e); },
        Ok(()) => {},
    }

    sleep.wait();

    Ok(())
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]

use irc::event_stream::{Action, HandlerAction, Response};
use irc::protocol;
use regex::Regex;

extern crate env_logger;
extern crate irc;
extern crate regex;

#[macro_use]
extern crate log;

fn main() {
    env_logger::init().unwrap();

    let addr = ("irc.freenode.net", 6667);
    let nick = "rustbot_test";
    let channels = ["#rustbot_test"];

    // let addr = ("irc.freenode.net", 6667);
    // let nick = "hiphopabotamus";
    // let channels = ["#raptracks"];

    let echo_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(nick)) {
            if Regex::new(r"^[Hh]i$").ok().expect("bad regex").is_match(pm.msg) {
                if let Some(reply_to) = pm.reply_target(nick) {
                    if let Some(protocol::Source::User(ref user_info)) = pm.src {
                        return Response::respond(protocol::Privmsg::new(reply_to, &format!("Hi, {}!", user_info.nick)).format());
                    }
                }
            } else if Regex::new(r"^go away$").unwrap().is_match(pm.msg) {
                return Response(None, HandlerAction::Keep, Action::Stop);
            }
        }
        Response::nothing()
    };

    let (mut client, join_handle) = irc::Client::connect(
        &addr, nick, &channels, "rustbot", "rust irc robot")
        .ok().expect(&format!("Error connecting to {:?}.", addr));

    client.add_handler(echo_handler);
    join_handle.join().unwrap_or_else(|_| {
        error!("Unknown error!");
    });
}
<commit_msg>removed cruft<commit_after>#![feature(box_syntax)]

use irc::event_stream::{Action, HandlerAction, Response};
use irc::protocol;
use regex::Regex;

extern crate env_logger;
extern crate irc;
extern crate regex;

#[macro_use]
extern crate log;

fn main() {
    env_logger::init().unwrap();

    let addr = ("irc.freenode.net", 6667);
    let nick = "rustbot_test";
    let channels = ["#rustbot_test"];

    let echo_handler = box move |line: &str| {
        if let Some(pm) = protocol::Privmsg::parse(line).and_then(|pm| pm.targeted_msg(nick)) {
            if Regex::new(r"^[Hh]i$").ok().expect("bad regex").is_match(pm.msg) {
                if let Some(reply_to) = pm.reply_target(nick) {
                    if let Some(protocol::Source::User(ref user_info)) = pm.src {
                        return Response::respond(protocol::Privmsg::new(reply_to, &format!("Hi, {}!", user_info.nick)).format());
                    }
                }
            } else if Regex::new(r"^go away$").unwrap().is_match(pm.msg) {
                return Response(None, HandlerAction::Keep, Action::Stop);
            }
        }
        Response::nothing()
    };

    let (mut client, join_handle) = irc::Client::connect(
        &addr, nick, &channels, "rustbot", "rust irc robot")
        .ok().expect(&format!("Error connecting to {:?}.", addr));

    client.add_handler(echo_handler);
    join_handle.join().unwrap_or_else(|_| {
        error!("Unknown error!");
    });
}
<|endoftext|>


<commit_before>
extern crate glutin;
extern crate glium;
extern crate image;
extern crate clock_ticks;
extern crate uil;

use std::old_io::{File, BufferedReader, BufReader};
use glium::{DisplayBuild, Surface};
use uil::layout;
use uil::rendering;
use std::old_io::timer;
use std::time::duration::Duration;

fn main() {

    //////////////////////////////////////////////////////////////////////////////
    // uil related code
    //
    let library = {
        let file = File::open(&Path::new("./examples/menu.markup")).unwrap();
        let reader = BufferedReader::new(file);
        uil::markup::parse(uil::StdOutErrorReporter, reader)
    };

    let styledefs = {
        let file = File::open(&Path::new("./examples/menu.deps")).unwrap();
        let reader = BufferedReader::new(file);
        uil::deps::parse(uil::StdOutErrorReporter, reader)
    };

    let stylesheet = {
        let file = File::open(&Path::new("./examples/menu.style")).unwrap();
        let reader = BufferedReader::new(file);
        uil::style::parse(uil::StdOutErrorReporter, reader, &styledefs)
    };

    //////////////////////////////////////////////////////////////////////////////
    // glium related code
    //
    let display = glutin::WindowBuilder::new()
        .with_vsync()
        .build_glium()
        .unwrap();

    let (width, height) = display.get_window().unwrap().get_inner_size().unwrap();

    let mut renderer = uil::backend::GliumRenderer::new(&display);
    let mut router = uil::Router::from_library_and_stylesheet(&display, library, &stylesheet);

    //////////////////////////////////////////////////////////////////////////////
    // main loop (modified example from glium lib)
    //
    start_loop(|| {

        // Update views
        router.update(uil::Viewport { width: width as f32, height: height as f32 });

        // Render views
        router.render_views(&mut renderer);

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return Action::Stop,
                _ => ()
            }
        }

        Action::Continue
    });
}

pub enum Action {
    Stop,
    Continue,
}

pub fn start_loop<F>(mut callback: F) where F: FnMut() -> Action {
    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    loop {
        match callback() {
            Action::Stop => break,
            Action::Continue => ()
        };
        let now = clock_ticks::precise_time_ns();
        accumulator += now - previous_clock;
        previous_clock = now;
        const FIXED_TIME_STAMP: u64 = 16666667;
        while accumulator >= FIXED_TIME_STAMP {
            accumulator -= FIXED_TIME_STAMP;
            // if you have a game, update the state here
        }
        timer::sleep(Duration::nanoseconds((FIXED_TIME_STAMP - accumulator) as i64));
    }
}
<commit_msg>Fixed example to compile with latest rustc and latest uil-rs.<commit_after>#![feature(old_io, std_misc)]

extern crate glutin;
extern crate glium;
extern crate image;
extern crate clock_ticks;
extern crate uil;

use std::io::BufReader;
use std::fs::File;
use std::path::Path;
use glium::{DisplayBuild, Surface};
use uil::layout;
use uil::rendering;
use std::old_io::timer;
use std::time::duration::Duration;

fn main() {

    //////////////////////////////////////////////////////////////////////////////
    // uil related code
    //
    let library = {
        let file = File::open(&Path::new("./examples/menu.markup")).unwrap();
        let reader = BufReader::new(file);
        uil::markup::parse(uil::StdOutErrorReporter, reader)
    };

    let styledefs = {
        let file = File::open(&Path::new("./examples/menu.deps")).unwrap();
        let reader = BufReader::new(file);
        uil::deps::parse(uil::StdOutErrorReporter, reader)
    };

    //////////////////////////////////////////////////////////////////////////////
    // glium display start
    //
    let display = glutin::WindowBuilder::new()
        .with_vsync()
        .build_glium()
        .unwrap();

    //////////////////////////////////////////////////////////////////////////////
    // uil resource manager and final tree
    //

    let mut resource_manager = uil::ResourceManager::new(&display);

    let stylesheet = {
        let file = File::open(&Path::new("./examples/menu.style")).unwrap();
        let reader = BufReader::new(file);
        uil::style::parse(uil::StdOutErrorReporter, reader, &styledefs, &mut resource_manager)
    };

    let (width, height) = display.get_window().unwrap().get_inner_size().unwrap();

    let mut renderer = uil::backend::GliumRenderer::new(&display);
    let mut router = uil::Router::from_library_and_stylesheet(
        &display,
        &resource_manager,
        library,
        &stylesheet
    );

    //////////////////////////////////////////////////////////////////////////////
    // main loop (modified example from glium lib)
    //
    start_loop(|| {

        // Update views
        router.update(uil::Viewport { width: width as f32, height: height as f32 });

        // Render views
        router.render_views(&mut renderer, &resource_manager);

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return Action::Stop,
                _ => ()
            }
        }

        Action::Continue
    });
}

pub enum Action {
    Stop,
    Continue,
}

pub fn start_loop<F>(mut callback: F) where F: FnMut() -> Action {
    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    loop {
        match callback() {
            Action::Stop => break,
            Action::Continue => ()
        };
        let now = clock_ticks::precise_time_ns();
        accumulator += now - previous_clock;
        previous_clock = now;
        const FIXED_TIME_STAMP: u64 = 16666667;
        while accumulator >= FIXED_TIME_STAMP {
            accumulator -= FIXED_TIME_STAMP;
            // if you have a game, update the state here
        }
        timer::sleep(Duration::nanoseconds((FIXED_TIME_STAMP - accumulator) as i64));
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::AbstractBuffer;
use format::Format;
use memory::MemorySourceChunk;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. More precisely, a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

pub struct AttributeInfo {
    pub offset: usize,
    pub format: Format,
}

/// Trait for types that contain the definition of the vertex input.
pub unsafe trait Definition {
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer in which the attribute
    /// is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

pub unsafe trait Source<L>: Definition {
    type Iter: ExactSizeIterator<Item = Arc<AbstractBuffer>>;

    /// Returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, M> Source<&'a Arc<Buffer<[V], M>>> for SingleBufferDefinition<V>
    where V: Vertex + 'static, M: MemorySourceChunk + 'static
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<Buffer<[V], M>>)
              -> (OptionIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

// TODO: shouldn't be just `Two` be `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/*pub struct OneVertexOneInstanceDefinition<V, I>;

unsafe impl<V, I> Definition for OneVertexOneInstanceDefinition<V, I>
    where V: Vertex, I: Vertex
{
    type InfoIter = OptionIntoIter<(u32, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(u32, AttributeInfo)> {
        Vertex::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, S> Source<S> for OneVertexOneInstanceDefinition<V>
    where V: Vertex, S: Into<BufferSlice<'a, [V]>>
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn iter(&self, source: S) -> OptionIntoIter<Arc<AbstractBuffer>> {
        let source = source.into();
        assert!(source.offset() == 0);      // TODO: not supported otherwise
        Some(source.buffer().clone() as Arc<_>).into_iter()
    }

    #[inline]
    fn num_vertices(&self, source: S) -> usize {
        source.into().len()
    }
}*/

#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

pub unsafe trait Data {
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}
<commit_msg>Add OneVertexOneInstanceDefinition<commit_after>use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::AbstractBuffer;
use format::Format;
use memory::MemorySourceChunk;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. More precisely, a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

pub struct AttributeInfo {
    pub offset: usize,
    pub format: Format,
}

/// Trait for types that contain the definition of the vertex input.
pub unsafe trait Definition {
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer in which the attribute
    /// is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

pub unsafe trait Source<L>: Definition {
    type Iter: ExactSizeIterator<Item = Arc<AbstractBuffer>>;

    /// Returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, M> Source<&'a Arc<Buffer<[V], M>>> for SingleBufferDefinition<V>
    where V: Vertex + 'static, M: MemorySourceChunk + 'static
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<Buffer<[V], M>>)
              -> (OptionIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

pub unsafe trait Data {
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::AbstractBuffer;
use format::Format;
use memory::MemorySourceChunk;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. More precisely, a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

pub struct AttributeInfo {
    pub offset: usize,
    pub format: Format,
}

/// Trait for types that contain the definition of the vertex input.
pub unsafe trait Definition {
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer in which the attribute
    /// is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

pub unsafe trait Source<L>: Definition {
    type Iter: ExactSizeIterator<Item = Arc<AbstractBuffer>>;

    /// Returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, M> Source<&'a Arc<Buffer<[V], M>>> for SingleBufferDefinition<V>
    where V: Vertex + 'static, M: MemorySourceChunk + 'static
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<Buffer<[V], M>>)
              -> (OptionIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

pub unsafe trait Data {
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}
<commit_msg>Add some docs to the vertex module<commit_after>//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `Definition` trait.
//!
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `Definition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```no_run
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::Buffer;
//! use vulkano::buffer::Usage as BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = unsafe { std::mem::uninitialized() };
//! # let queue: Arc<Queue> = unsafe { std::mem::uninitialized() };
//!
//! struct Vertex {
//!     position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//!     vertex_buffer: true,
//!     .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = Buffer::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//!                                                     .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
//!
use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::AbstractBuffer;
use format::Format;
use memory::MemorySourceChunk;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

/// Information about a single attribute within a vertex.
pub struct AttributeInfo {
    /// Number of bytes between the start of a vertex and the location of attribute.
    pub offset: usize,
    /// Data type of the attribute.
    pub format: Format,
}

/// Trait for types that contain a definition of the vertex input used by a graphics pipeline.
pub unsafe trait Definition {
    /// Iterator used to enumerate the list of buffers.
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer (within the iterator
    /// returned by `buffers`) in which the attribute is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

/// Extension for `Definition` trait. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait Source<L>: Definition {
    /// Iterator used by `decode`.
    type Iter: ExactSizeIterator<Item = Arc<AbstractBuffer>>;

    /// Checks and returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

/// Implementation of `Definition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, M> Source<&'a Arc<Buffer<[V], M>>> for SingleBufferDefinition<V>
    where V: Vertex + 'static, M: MemorySourceChunk + 'static
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<Buffer<[V], M>>)
              -> (OptionIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

/// Trait for data types that can be used as vertex attributes. Used by the `impl_vertex!` macro.
pub unsafe trait Data {
    /// Returns the format of the attribute.
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// uart_blocking_read.rs - Blocks while waiting for incoming serial data.

use std::error::Error;
use std::time::Duration;

use rppal::uart::{Parity, Uart};

fn main() -> Result<(), Box<dyn Error>> {
    // Connect to the primary UART and configure it for 115.2 kbit/s, no
    // parity bit, 8 data bits and 1 stop bit.
    let mut uart = Uart::new(115_200, Parity::None, 8, 1)?;

    // Configure read() to wait until at least 1 byte becomes available
    // in the incoming buffer.
    uart.set_blocking_mode(1, Duration::default())?;

    let mut buffer = [0u8; 1];
    loop {
        // Fill the buffer variable with any incoming data.
        if uart.read(&mut buffer)? > 0 {
            println!("Received byte: {}", buffer[0]);
        }
    }
}
<commit_msg>Update documentation<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// uart_blocking_read.rs - Blocks while waiting for incoming serial data.

use std::error::Error;
use std::time::Duration;

use rppal::uart::{Parity, Uart};

fn main() -> Result<(), Box<dyn Error>> {
    // Connect to the primary UART and configure it for 115.2 kbit/s, no
    // parity bit, 8 data bits and 1 stop bit.
    let mut uart = Uart::new(115_200, Parity::None, 8, 1)?;

    // Configure read() to block until at least 1 byte is received.
    uart.set_blocking_mode(1, Duration::default())?;

    let mut buffer = [0u8; 1];
    loop {
        // Fill the buffer variable with any incoming data.
        if uart.read(&mut buffer)? > 0 {
            println!("Received byte: {}", buffer[0]);
        }
    }
}
<|endoftext|>


<commit_before>use core::fmt::Debug;
use std::any::Any;

use progress::Timestamp;
use progress::count_map::CountMap;

use communication::Observer;
use communication::observer::{BufferedObserver, FlattenedObserver, BroadcastObserver};

use std::rc::Rc;
use std::cell::RefCell;

pub trait Data : Clone+Send+Debug+Any { }
impl<T: Clone+Send+Debug+Any> Data for T { }

pub struct OutputPort<T: Timestamp, D: Data> {
    // shared:    Rc<RefCell<Vec<Box<Observer<Time=T, Data=D>>>>>,
    shared: BufferedObserver<D, Rc<RefCell<BroadcastObserver<Box<Observer<Time=T, Data=Vec<D>>>>>>>,
}

impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) { self.shared.open(time); }
    #[inline(always)] fn show(&mut self, data: &D) { self.shared.show(data); }
    #[inline(always)] fn give(&mut self, data:  D) { self.shared.give(data); }
    #[inline(always)] fn shut(&mut self, time: &T) { self.shared.shut(time); }
}

impl<T: Timestamp, D: Data> OutputPort<T, D> {
    pub fn new() -> OutputPort<T, D> {
        OutputPort { shared: BufferedObserver::new(256, Rc::new(RefCell::new(BroadcastObserver::new()))) }
    }
    pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
        self.shared.inner().borrow_mut().add(Box::new(FlattenedObserver::new(observer)));
    }
}

// TODO : un-implement, and have 'new' return a pair of pub/sub types
impl<T: Timestamp, D: Data> Clone for OutputPort<T, D> {
    fn clone(&self) -> OutputPort<T, D> {
        OutputPort { shared: BufferedObserver::new(256, self.shared.inner().clone()) }
    }
}

pub struct ObserverHelper<O: Observer> {
    observer:   O,
    counts:     Rc<RefCell<CountMap<O::Time>>>,
    count:      i64,
}

impl<O: Observer> Observer for ObserverHelper<O> where O::Time : Timestamp {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { self.count += 1; self.observer.show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { self.count += 1; self.observer.give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () {
        self.counts.borrow_mut().update(time, self.count);
        self.observer.shut(time);
        self.count = 0;
    }
}

impl<O: Observer> ObserverHelper<O> where O::Time : Eq+Clone+'static {
    pub fn new(observer: O, counts: Rc<RefCell<CountMap<O::Time>>>) -> ObserverHelper<O> {
        ObserverHelper {
            observer:   observer,
            counts:     counts,
            count:      0,
        }
    }

    #[inline(always)] pub fn pull_progress(&mut self, updates: &mut CountMap<O::Time>) {
        while let Some((ref time, delta)) = self.counts.borrow_mut().pop() { updates.update(time, delta); }
    }
}
<commit_msg>OutputPort now pools buffers with a FlattenObserver to avoid allocations/clones<commit_after>use core::fmt::Debug;
use std::any::Any;
use std::mem;

use progress::Timestamp;
use progress::count_map::CountMap;

use communication::Observer;
// use communication::observer::{BufferedObserver, OutputPortFlattener, BroadcastObserver};

use std::rc::Rc;
use std::cell::RefCell;

pub trait Data : Clone+Send+Debug+Any { }
impl<T: Clone+Send+Debug+Any> Data for T { }

// TODO : All the buffering, cloning, and dropping makes pandas sad.
// TODO : It should be easy enough to Rc<RefCell<Vec<Vec<D>>>> things up.
// TODO : OutputPort can do the buffering, broadcasting, and collecting vecs.
// pub struct OutputPort<T: Timestamp, D: Data> {
//     shared: BufferedObserver<D, Rc<RefCell<BroadcastObserver<Box<Observer<Time=T, Data=Vec<D>>>>>>>,
// }
//
// impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
//     type Time = T;
//     type Data = D;
//     #[inline(always)] fn open(&mut self, time: &T) { self.shared.open(time); }
//     #[inline(always)] fn show(&mut self, data: &D) { self.shared.show(data); }
//     #[inline(always)] fn give(&mut self, data:  D) { self.shared.give(data); }
//     #[inline(always)] fn shut(&mut self, time: &T) { self.shared.shut(time); }
// }
//
// impl<T: Timestamp, D: Data> OutputPort<T, D> {
//     pub fn new() -> OutputPort<T, D> {
//         OutputPort { shared: BufferedObserver::new(256, Rc::new(RefCell::new(BroadcastObserver::new()))) }
//     }
//     pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
//         self.shared.inner().borrow_mut().add(Box::new(OutputPortFlattener::new(observer)));
//     }
// }

pub struct OutputPort<T: Timestamp, D: Data> {
    limit:  usize,
    buffer: Vec<D>,
    shared: Rc<RefCell<Vec<Box<Observer<Time=T,Data=Vec<D>>>>>>,
    stash:  Rc<RefCell<Vec<Vec<D>>>>,
}

impl<T: Timestamp, D: Data> Observer for OutputPort<T, D> {
    type Time = T;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &T) {
        for observer in self.shared.borrow_mut().iter_mut() {
            observer.open(time);
        }
    }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.buffer.push(data);
        if self.buffer.len() > self.limit {
            let mut observers = self.shared.borrow_mut();
            // let mut supply = self.stash.borrow_mut();
            for index in (0..observers.len()) {
                let data = mem::replace(&mut self.buffer, self.stash.borrow_mut().pop().unwrap_or(Vec::new()));
                if index < observers.len() - 1 { self.buffer.push_all(&data); }
                observers[index].give(data);
            }
        }
    }
    #[inline(always)] fn shut(&mut self, time: &T) {
        if self.buffer.len() > 0 {
            let mut observers = self.shared.borrow_mut();
            // let mut supply = ;
            for index in (0..observers.len()) {
                let data = mem::replace(&mut self.buffer, self.stash.borrow_mut().pop().unwrap_or(Vec::new()));
                if index < observers.len() - 1 { self.buffer.push_all(&data); }
                observers[index].give(data);
            }
        }

        for observer in self.shared.borrow_mut().iter_mut() {
            observer.shut(time);
        }
    }
}

impl<T: Timestamp, D: Data> OutputPort<T, D> {
    pub fn new() -> OutputPort<T, D> {
        let limit = 256;
        OutputPort {
            limit:  limit,
            buffer: Vec::with_capacity(limit),
            shared: Rc::new(RefCell::new(Vec::new())),
            stash:  Rc::new(RefCell::new(Vec::new())),
        }
            // shared: BufferedObserver::new(256, Rc::new(RefCell::new(BroadcastObserver::new()))) }
    }
    pub fn add_observer<O: Observer<Time=T, Data=D>+'static>(&self, observer: O) {
        self.shared.borrow_mut().push(Box::new(OutputPortFlattener::new(observer, self.stash.clone())));
    }
}

// TODO : un-implement, and have 'new' return a pair of pub/sub types
impl<T: Timestamp, D: Data> Clone for OutputPort<T, D> {
    fn clone(&self) -> OutputPort<T, D> {
        OutputPort {
            limit:  self.limit,
            buffer: Vec::new(),
            shared: self.shared.clone(),
            stash:  self.stash.clone(),
        }
    }
}

// dual to BufferedObserver, flattens out buffers
pub struct OutputPortFlattener<O: Observer> {
    observer:   O,
    stash:      Rc<RefCell<Vec<Vec<O::Data>>>>,
}

impl<O: Observer> OutputPortFlattener<O> {
    pub fn new(observer: O, stash: Rc<RefCell<Vec<Vec<O::Data>>>>) -> OutputPortFlattener<O> {
        OutputPortFlattener {
            observer: observer,
            stash:    stash,
        }
    }
}

impl<O: Observer> Observer for OutputPortFlattener<O> {
    type Time = O::Time;
    type Data = Vec<O::Data>;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, _data: &Vec<O::Data>) -> () { panic!("something horribly wrong!") }
    #[inline(always)] fn give(&mut self, mut data:  Vec<O::Data>) -> () {
        for datum in data.drain() { self.observer.give(datum); }
        self.stash.borrow_mut().push(data);
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { self.observer.shut(time); }
}

pub struct ObserverHelper<O: Observer> {
    observer:   O,
    counts:     Rc<RefCell<CountMap<O::Time>>>,
    count:      i64,
}

impl<O: Observer> Observer for ObserverHelper<O> where O::Time : Timestamp {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { self.count += 1; self.observer.show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { self.count += 1; self.observer.give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () {
        self.counts.borrow_mut().update(time, self.count);
        self.observer.shut(time);
        self.count = 0;
    }
}

impl<O: Observer> ObserverHelper<O> where O::Time : Eq+Clone+'static {
    pub fn new(observer: O, counts: Rc<RefCell<CountMap<O::Time>>>) -> ObserverHelper<O> {
        ObserverHelper {
            observer:   observer,
            counts:     counts,
            count:      0,
        }
    }

    #[inline(always)] pub fn pull_progress(&mut self, updates: &mut CountMap<O::Time>) {
        while let Some((ref time, delta)) = self.counts.borrow_mut().pop() { updates.update(time, delta); }
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#![feature(async_closure)]

pub mod grpc;
pub mod logger;
pub mod lookup;
pub mod lookup_data;
#[cfg(feature = "oak-metrics")]
pub mod metrics;
pub mod server;
#[cfg(feature = "oak-tf")]
pub mod tf;

#[cfg(feature = "oak-metrics")]
use crate::metrics::PrivateMetricsProxyFactory;
#[cfg(feature = "oak-tf")]
use crate::tf::{read_model_from_path, TensorFlowFactory};
use crate::{
    grpc::{create_and_start_grpc_server, create_wasm_handler, RequestModel},
    logger::Logger,
    lookup::LookupFactory,
    lookup_data::{LookupData, LookupDataAuth, LookupDataSource},
    server::Policy,
};
use anyhow::Context;
use clap::Parser;
use log::Level;
use oak_functions_abi::proto::{ConfigurationInfo, ServerPolicy};
#[cfg(feature = "oak-metrics")]
use oak_functions_metrics::PrivateMetricsConfig;
#[cfg(feature = "oak-tf")]
use oak_functions_tf_inference::TensorFlowModelConfig;
use oak_logger::OakLogger;
use oak_remote_attestation::crypto::get_sha256;
use serde_derive::Deserialize;
use std::{
    fs,
    net::{Ipv6Addr, SocketAddr},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    time::Duration,
};

#[cfg(test)]
mod tests;

#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Config {
    /// URL of a file containing key / value entries in protobuf binary format for lookup.
    ///
    /// If empty or not provided, no data is available for lookup.
    #[serde(default)]
    lookup_data: Option<Data>,
    /// How often to refresh the lookup data.
    ///
    /// If empty or not provided, data is only loaded once at startup.
    #[serde(default, with = "humantime_serde")]
    lookup_data_download_period: Option<Duration>,
    /// Whether to use the GCP metadata service to obtain an authentication token for downloading
    /// the lookup data.
    #[serde(default = "LookupDataAuth::default")]
    lookup_data_auth: LookupDataAuth,
    /// Number of worker threads available to the async runtime.
    ///
    /// Defaults to 4 if unset.
    ///
    /// Note that the CPU core detection logic does not seem to work reliably on Google Cloud Run,
    /// so it is advisable to set this value to the number of cores available on the Cloud Run
    /// instance.
    ///
    /// See <https://docs.rs/tokio/1.5.0/tokio/runtime/struct.Builder.html#method.worker_threads>.
    worker_threads: Option<usize>,
    /// Security policy guaranteed by the server.
    policy: Option<Policy>,
    /// Configuration for TensorFlow model
    #[cfg(feature = "oak-tf")]
    #[serde(default)]
    tf_model: Option<TensorFlowModelConfig>,
    /// Differentially private metrics configuration.
    #[cfg(feature = "oak-metrics")]
    #[serde(default)]
    metrics: Option<PrivateMetricsConfig>,
    /// Request model used to accept gRPC client requests
    #[serde(default = "RequestModel::default")]
    grpc_request_model: RequestModel,
}

#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
enum Data {
    /// Download data file via HTTP GET.
    /// Supported URL schemes: `http`, `https`.
    Url(String),
    /// Read data file from the local file system.
    /// File path is relative to the current `$PWD` (*not* relative to the config file).
    File(String),
}

/// Command line options for the Oak loader.
///
/// In general, when adding new configuration parameters, they should go in the `Config` struct
/// instead of here, and provided as part of the config TOML file by the developer, who would
/// normally bundle it with the Docker image of the Oak Functions Loader.
#[derive(Parser, Clone, Debug)]
#[clap(about = "Oak Functions Loader")]
pub struct Opt {
    #[clap(
        long,
        default_value = "8080",
        help = "Port number that the server listens on."
    )]
    http_listen_port: u16,
    #[clap(
        long,
        help = "Path to a Wasm file to be loaded and executed per invocation. The Wasm module must export a function named `main`."
    )]
    wasm_path: String,
    #[clap(
        long,
        help = "Path to a file containing configuration parameters in TOML format."
    )]
    config_path: String,
}

async fn background_refresh_lookup_data(
    lookup_data: &LookupData,
    period: Duration,
    logger: &Logger,
) {
    // Create an interval that starts after `period`, since the data was already refreshed
    // initially.
    let mut interval = tokio::time::interval_at(tokio::time::Instant::now() + period, period);
    loop {
        interval.tick().await;
        // If there is an error, we skip the current refresh and wait for the next tick.
        if let Err(err) = lookup_data.refresh().await {
            logger.log_public(
                Level::Error,
                &format!("error refreshing lookup data: {}", err),
            );
        }
    }
}

/// This crate is just a library so this function does not get executed directly by anything, it
/// needs to be wrapped in the "actual" `main` from a bin crate.
pub fn lib_main() -> anyhow::Result<()> {
    let opt = Opt::parse();
    let config_file_bytes = fs::read(&opt.config_path)
        .with_context(|| format!("Couldn't read config file {}", &opt.config_path))?;
    let config: Config =
        toml::from_slice(&config_file_bytes).context("Couldn't parse config file")?;
    // TODO(#1971): Make maximum log level configurable.
    let logger = Logger::default();
    logger.log_public(Level::Info, &format!("parsed config file:\n{:#?}", config));
    tokio::runtime::Builder::new_multi_thread()
        .worker_threads(config.worker_threads.unwrap_or(4))
        .enable_all()
        .build()
        .unwrap()
        .block_on(async_main(opt, config, logger))
}

/// Main execution point for the Oak Functions Loader.
async fn async_main(opt: Opt, config: Config, logger: Logger) -> anyhow::Result<()> {
    let (notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();

    let lookup_data = load_lookup_data(&config, logger.clone()).await?;

    #[allow(unused_mut)]
    let mut extensions = Vec::new();

    let lookup_factory = LookupFactory::new_boxed_extension_factory(lookup_data, logger.clone())?;
    extensions.push(lookup_factory);

    #[cfg(feature = "oak-tf")]
    if let Some(tf_model_config) = &config.tf_model {
        // Load the TensorFlow model from the given path in the config
        let model = read_model_from_path(&tf_model_config.path)?;
        let tf_model_factory = TensorFlowFactory::new_boxed_extension_factory(
            model,
            tf_model_config.shape.clone(),
            logger.clone(),
        )?;
        extensions.push(tf_model_factory);
    }

    #[cfg(feature = "oak-metrics")]
    if let Some(metrics_config) = &config.metrics {
        let metrics_factory = PrivateMetricsProxyFactory::new_boxed_extension_factory(
            metrics_config,
            logger.clone(),
        )?;
        extensions.push(metrics_factory);
    }

    let wasm_module_bytes = fs::read(&opt.wasm_path)
        .with_context(|| format!("Couldn't read Wasm file {}", &opt.wasm_path))?;

    // Make sure that a policy is specified and is valid.
    let policy = config
        .policy
        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("a valid policy must be provided"))
        .and_then(|policy| policy.validate())?;

    let address = SocketAddr::from((Ipv6Addr::UNSPECIFIED, opt.http_listen_port));
    let tee_certificate = vec![];

    let wasm_handler = create_wasm_handler(&wasm_module_bytes, extensions, logger.clone())?;

    let config_info = get_config_info(&wasm_module_bytes, policy.clone(), &config)?;

    // Start server.
    let server_handle = tokio::spawn(async move {
        create_and_start_grpc_server(
            &address,
            wasm_handler,
            tee_certificate,
            policy.clone(),
            config_info,
            async { notify_receiver.await.unwrap() },
            logger,
            config.grpc_request_model,
        )
        .await
        .context("error while waiting for the server to terminate")
    });

    // Wait for the termination signal.
    let done = Arc::new(AtomicBool::new(false));
    signal_hook::flag::register(signal_hook::consts::signal::SIGINT, Arc::clone(&done))
        .context("could not register signal handler")?;

    // The server is started in its own thread, so just block the current thread until a signal
    // arrives. This is needed for getting the correct status code when running with `xtask`.
    while !done.load(Ordering::Relaxed) {
        // There are few synchronization mechanisms that are allowed to be used in a signal
        // handler context, so use a primitive sleep loop to watch for the termination
        // notification (rather than something more accurate like `std::sync::Condvar`).
        // See e.g.: http://man7.org/linux/man-pages/man7/signal-safety.7.html
        std::thread::sleep(std::time::Duration::from_millis(100));
    }

    notify_sender
        .send(())
        .expect("Couldn't send completion signal.");

    server_handle
        .await
        .context("error while waiting for the server to terminate")?
}

async fn load_lookup_data(config: &Config, logger: Logger) -> anyhow::Result<Arc<LookupData>> {
    let lookup_data_source = match &config.lookup_data {
        Some(lookup_data) => match &lookup_data {
            Data::Url(url_string) => {
                let url = url::Url::parse(url_string).context("Couldn't parse lookup data URL")?;
                match url.scheme() {
                    "http" | "https" => Some(LookupDataSource::Http {
                        url: url_string.clone(),
                        auth: config.lookup_data_auth,
                    }),
                    scheme => anyhow::bail!(
                        "Unknown URL scheme in lookup data: expected 'http' or 'https', found {}",
                        scheme
                    ),
                }
            }
            Data::File(path) => Some(LookupDataSource::File(path.clone().into())),
        },
        None => None,
    };
    let lookup_data = Arc::new(LookupData::new_empty(
        lookup_data_source.clone(),
        logger.clone(),
    ));
    if lookup_data_source.is_some() {
        // First load the lookup data upfront in a blocking fashion.
        // TODO(#1930): Retry the initial lookup a few times if it fails.
        lookup_data
            .refresh()
            .await
            .context("Couldn't perform initial load of lookup data")?;
        if let Some(lookup_data_download_period) = config.lookup_data_download_period {
            // Create background task to periodically refresh the lookup data.
            let lookup_data = lookup_data.clone();
            let logger = logger.clone();
            tokio::spawn(async move {
                background_refresh_lookup_data(&lookup_data, lookup_data_download_period, &logger)
                    .await
            });
        };
    }
    Ok(lookup_data)
}

#[allow(unused_variables)]
fn get_config_info(
    wasm_module_bytes: &[u8],
    policy: ServerPolicy,
    config: &Config,
) -> anyhow::Result<ConfigurationInfo> {
    #[cfg(feature = "oak-metrics")]
    let metrics = match &config.metrics {
        Some(ref metrics_config) => Some(oak_functions_abi::proto::PrivateMetricsConfig {
            epsilon: metrics_config.epsilon,
            batch_size: metrics_config
                .batch_size
                .try_into()
                .context("could not convert usize to u32")?,
        }),
        None => None,
    };
    #[cfg(not(feature = "oak-metrics"))]
    let metrics = None;

    #[cfg(feature = "oak-tf")]
    let ml_inference = config.tf_model.is_some();
    #[cfg(not(feature = "oak-tf"))]
    let ml_inference = false;

    Ok(ConfigurationInfo {
        wasm_hash: get_sha256(wasm_module_bytes).to_vec(),
        policy: Some(policy),
        ml_inference,
        metrics,
    })
}
<commit_msg>Add comment explaining config behevaior and rationale (#2585)<commit_after>//
// Copyright 2021 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#![feature(async_closure)]

pub mod grpc;
pub mod logger;
pub mod lookup;
pub mod lookup_data;
#[cfg(feature = "oak-metrics")]
pub mod metrics;
pub mod server;
#[cfg(feature = "oak-tf")]
pub mod tf;

#[cfg(feature = "oak-metrics")]
use crate::metrics::PrivateMetricsProxyFactory;
#[cfg(feature = "oak-tf")]
use crate::tf::{read_model_from_path, TensorFlowFactory};
use crate::{
    grpc::{create_and_start_grpc_server, create_wasm_handler, RequestModel},
    logger::Logger,
    lookup::LookupFactory,
    lookup_data::{LookupData, LookupDataAuth, LookupDataSource},
    server::Policy,
};
use anyhow::Context;
use clap::Parser;
use log::Level;
use oak_functions_abi::proto::{ConfigurationInfo, ServerPolicy};
#[cfg(feature = "oak-metrics")]
use oak_functions_metrics::PrivateMetricsConfig;
#[cfg(feature = "oak-tf")]
use oak_functions_tf_inference::TensorFlowModelConfig;
use oak_logger::OakLogger;
use oak_remote_attestation::crypto::get_sha256;
use serde_derive::Deserialize;
use std::{
    fs,
    net::{Ipv6Addr, SocketAddr},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    time::Duration,
};

#[cfg(test)]
mod tests;

/// Runtime Configuration of Runtime.
///
/// This struct serves as a schema for a static TOML config file provided by
/// application developers. In deployment, this static config file is typically
/// bundled with the Oak Runtime binary. Config values captured in it serve
/// as a type safe version of regular command line flags.
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Config {
    /// URL of a file containing key / value entries in protobuf binary format for lookup.
    ///
    /// If empty or not provided, no data is available for lookup.
    #[serde(default)]
    lookup_data: Option<Data>,
    /// How often to refresh the lookup data.
    ///
    /// If empty or not provided, data is only loaded once at startup.
    #[serde(default, with = "humantime_serde")]
    lookup_data_download_period: Option<Duration>,
    /// Whether to use the GCP metadata service to obtain an authentication token for downloading
    /// the lookup data.
    #[serde(default = "LookupDataAuth::default")]
    lookup_data_auth: LookupDataAuth,
    /// Number of worker threads available to the async runtime.
    ///
    /// Defaults to 4 if unset.
    ///
    /// Note that the CPU core detection logic does not seem to work reliably on Google Cloud Run,
    /// so it is advisable to set this value to the number of cores available on the Cloud Run
    /// instance.
    ///
    /// See <https://docs.rs/tokio/1.5.0/tokio/runtime/struct.Builder.html#method.worker_threads>.
    worker_threads: Option<usize>,
    /// Security policy guaranteed by the server.
    policy: Option<Policy>,
    /// Configuration for TensorFlow model
    #[cfg(feature = "oak-tf")]
    #[serde(default)]
    tf_model: Option<TensorFlowModelConfig>,
    /// Differentially private metrics configuration.
    #[cfg(feature = "oak-metrics")]
    #[serde(default)]
    metrics: Option<PrivateMetricsConfig>,
    /// Request model used to accept gRPC client requests
    #[serde(default = "RequestModel::default")]
    grpc_request_model: RequestModel,
}

#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
enum Data {
    /// Download data file via HTTP GET.
    /// Supported URL schemes: `http`, `https`.
    Url(String),
    /// Read data file from the local file system.
    /// File path is relative to the current `$PWD` (*not* relative to the config file).
    File(String),
}

/// Command line options for the Oak loader.
///
/// In general, when adding new configuration parameters, they should go in the `Config` struct
/// instead of here.
#[derive(Parser, Clone, Debug)]
#[clap(about = "Oak Functions Loader")]
pub struct Opt {
    #[clap(
        long,
        default_value = "8080",
        help = "Port number that the server listens on."
    )]
    http_listen_port: u16,
    #[clap(
        long,
        help = "Path to a Wasm file to be loaded and executed per invocation. The Wasm module must export a function named `main`."
    )]
    wasm_path: String,
    #[clap(
        long,
        help = "Path to a file containing configuration parameters in TOML format."
    )]
    config_path: String,
}

async fn background_refresh_lookup_data(
    lookup_data: &LookupData,
    period: Duration,
    logger: &Logger,
) {
    // Create an interval that starts after `period`, since the data was already refreshed
    // initially.
    let mut interval = tokio::time::interval_at(tokio::time::Instant::now() + period, period);
    loop {
        interval.tick().await;
        // If there is an error, we skip the current refresh and wait for the next tick.
        if let Err(err) = lookup_data.refresh().await {
            logger.log_public(
                Level::Error,
                &format!("error refreshing lookup data: {}", err),
            );
        }
    }
}

/// This crate is just a library so this function does not get executed directly by anything, it
/// needs to be wrapped in the "actual" `main` from a bin crate.
pub fn lib_main() -> anyhow::Result<()> {
    let opt = Opt::parse();
    let config_file_bytes = fs::read(&opt.config_path)
        .with_context(|| format!("Couldn't read config file {}", &opt.config_path))?;
    let config: Config =
        toml::from_slice(&config_file_bytes).context("Couldn't parse config file")?;
    // TODO(#1971): Make maximum log level configurable.
    let logger = Logger::default();
    logger.log_public(Level::Info, &format!("parsed config file:\n{:#?}", config));
    tokio::runtime::Builder::new_multi_thread()
        .worker_threads(config.worker_threads.unwrap_or(4))
        .enable_all()
        .build()
        .unwrap()
        .block_on(async_main(opt, config, logger))
}

/// Main execution point for the Oak Functions Loader.
async fn async_main(opt: Opt, config: Config, logger: Logger) -> anyhow::Result<()> {
    let (notify_sender, notify_receiver) = tokio::sync::oneshot::channel::<()>();

    let lookup_data = load_lookup_data(&config, logger.clone()).await?;

    #[allow(unused_mut)]
    let mut extensions = Vec::new();

    let lookup_factory = LookupFactory::new_boxed_extension_factory(lookup_data, logger.clone())?;
    extensions.push(lookup_factory);

    #[cfg(feature = "oak-tf")]
    if let Some(tf_model_config) = &config.tf_model {
        // Load the TensorFlow model from the given path in the config
        let model = read_model_from_path(&tf_model_config.path)?;
        let tf_model_factory = TensorFlowFactory::new_boxed_extension_factory(
            model,
            tf_model_config.shape.clone(),
            logger.clone(),
        )?;
        extensions.push(tf_model_factory);
    }

    #[cfg(feature = "oak-metrics")]
    if let Some(metrics_config) = &config.metrics {
        let metrics_factory = PrivateMetricsProxyFactory::new_boxed_extension_factory(
            metrics_config,
            logger.clone(),
        )?;
        extensions.push(metrics_factory);
    }

    let wasm_module_bytes = fs::read(&opt.wasm_path)
        .with_context(|| format!("Couldn't read Wasm file {}", &opt.wasm_path))?;

    // Make sure that a policy is specified and is valid.
    let policy = config
        .policy
        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("a valid policy must be provided"))
        .and_then(|policy| policy.validate())?;

    let address = SocketAddr::from((Ipv6Addr::UNSPECIFIED, opt.http_listen_port));
    let tee_certificate = vec![];

    let wasm_handler = create_wasm_handler(&wasm_module_bytes, extensions, logger.clone())?;

    let config_info = get_config_info(&wasm_module_bytes, policy.clone(), &config)?;

    // Start server.
    let server_handle = tokio::spawn(async move {
        create_and_start_grpc_server(
            &address,
            wasm_handler,
            tee_certificate,
            policy.clone(),
            config_info,
            async { notify_receiver.await.unwrap() },
            logger,
            config.grpc_request_model,
        )
        .await
        .context("error while waiting for the server to terminate")
    });

    // Wait for the termination signal.
    let done = Arc::new(AtomicBool::new(false));
    signal_hook::flag::register(signal_hook::consts::signal::SIGINT, Arc::clone(&done))
        .context("could not register signal handler")?;

    // The server is started in its own thread, so just block the current thread until a signal
    // arrives. This is needed for getting the correct status code when running with `xtask`.
    while !done.load(Ordering::Relaxed) {
        // There are few synchronization mechanisms that are allowed to be used in a signal
        // handler context, so use a primitive sleep loop to watch for the termination
        // notification (rather than something more accurate like `std::sync::Condvar`).
        // See e.g.: http://man7.org/linux/man-pages/man7/signal-safety.7.html
        std::thread::sleep(std::time::Duration::from_millis(100));
    }

    notify_sender
        .send(())
        .expect("Couldn't send completion signal.");

    server_handle
        .await
        .context("error while waiting for the server to terminate")?
}

async fn load_lookup_data(config: &Config, logger: Logger) -> anyhow::Result<Arc<LookupData>> {
    let lookup_data_source = match &config.lookup_data {
        Some(lookup_data) => match &lookup_data {
            Data::Url(url_string) => {
                let url = url::Url::parse(url_string).context("Couldn't parse lookup data URL")?;
                match url.scheme() {
                    "http" | "https" => Some(LookupDataSource::Http {
                        url: url_string.clone(),
                        auth: config.lookup_data_auth,
                    }),
                    scheme => anyhow::bail!(
                        "Unknown URL scheme in lookup data: expected 'http' or 'https', found {}",
                        scheme
                    ),
                }
            }
            Data::File(path) => Some(LookupDataSource::File(path.clone().into())),
        },
        None => None,
    };
    let lookup_data = Arc::new(LookupData::new_empty(
        lookup_data_source.clone(),
        logger.clone(),
    ));
    if lookup_data_source.is_some() {
        // First load the lookup data upfront in a blocking fashion.
        // TODO(#1930): Retry the initial lookup a few times if it fails.
        lookup_data
            .refresh()
            .await
            .context("Couldn't perform initial load of lookup data")?;
        if let Some(lookup_data_download_period) = config.lookup_data_download_period {
            // Create background task to periodically refresh the lookup data.
            let lookup_data = lookup_data.clone();
            let logger = logger.clone();
            tokio::spawn(async move {
                background_refresh_lookup_data(&lookup_data, lookup_data_download_period, &logger)
                    .await
            });
        };
    }
    Ok(lookup_data)
}

#[allow(unused_variables)]
fn get_config_info(
    wasm_module_bytes: &[u8],
    policy: ServerPolicy,
    config: &Config,
) -> anyhow::Result<ConfigurationInfo> {
    #[cfg(feature = "oak-metrics")]
    let metrics = match &config.metrics {
        Some(ref metrics_config) => Some(oak_functions_abi::proto::PrivateMetricsConfig {
            epsilon: metrics_config.epsilon,
            batch_size: metrics_config
                .batch_size
                .try_into()
                .context("could not convert usize to u32")?,
        }),
        None => None,
    };
    #[cfg(not(feature = "oak-metrics"))]
    let metrics = None;

    #[cfg(feature = "oak-tf")]
    let ml_inference = config.tf_model.is_some();
    #[cfg(not(feature = "oak-tf"))]
    let ml_inference = false;

    Ok(ConfigurationInfo {
        wasm_hash: get_sha256(wasm_module_bytes).to_vec(),
        policy: Some(policy),
        ml_inference,
        metrics,
    })
}
<|endoftext|>


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

//! Routines for manipulating the control-flow graph.

use build::CFG;
use rustc::mir::*;

impl<'tcx> CFG<'tcx> {
    pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.basic_blocks[blk]
    }

    pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
        &mut self.basic_blocks[blk]
    }

    pub fn start_new_block(&mut self) -> BasicBlock {
        self.basic_blocks.push(BasicBlockData::new(None))
    }

    pub fn start_new_cleanup_block(&mut self) -> BasicBlock {
        let bb = self.start_new_block();
        self.block_data_mut(bb).is_cleanup = true;
        bb
    }

    pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
        debug!("push({:?}, {:?})", block, statement);
        self.block_data_mut(block).statements.push(statement);
    }

    pub fn push_assign(&mut self,
                       block: BasicBlock,
                       source_info: SourceInfo,
                       lvalue: &Lvalue<'tcx>,
                       rvalue: Rvalue<'tcx>) {
        self.push(block, Statement {
            source_info: source_info,
            kind: StatementKind::Assign(lvalue.clone(), rvalue)
        });
    }

    pub fn push_assign_constant(&mut self,
                                block: BasicBlock,
                                source_info: SourceInfo,
                                temp: &Lvalue<'tcx>,
                                constant: Constant<'tcx>) {
        self.push_assign(block, source_info, temp,
                         Rvalue::Use(Operand::Constant(constant)));
    }

    pub fn push_assign_unit(&mut self,
                            block: BasicBlock,
                            source_info: SourceInfo,
                            lvalue: &Lvalue<'tcx>) {
        self.push_assign(block, source_info, lvalue, Rvalue::Aggregate(
            AggregateKind::Tuple, vec![]
        ));
    }

    pub fn terminate(&mut self,
                     block: BasicBlock,
                     source_info: SourceInfo,
                     kind: TerminatorKind<'tcx>) {
        debug!("terminating block {:?} <- {:?}", block, kind);
        debug_assert!(self.block_data(block).terminator.is_none(),
                      "terminate: block {:?}={:?} already has a terminator set",
                      block,
                      self.block_data(block));
        self.block_data_mut(block).terminator = Some(Terminator {
            source_info: source_info,
            kind: kind,
        });
    }
}
<commit_msg>Rollup merge of #41015 - arielb1:new-block-stack, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Routines for manipulating the control-flow graph.

use build::CFG;
use rustc::mir::*;

impl<'tcx> CFG<'tcx> {
    pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
        &self.basic_blocks[blk]
    }

    pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
        &mut self.basic_blocks[blk]
    }

    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
    // it as #[inline(never)] to keep rustc's stack use in check.
    #[inline(never)]
    pub fn start_new_block(&mut self) -> BasicBlock {
        self.basic_blocks.push(BasicBlockData::new(None))
    }

    pub fn start_new_cleanup_block(&mut self) -> BasicBlock {
        let bb = self.start_new_block();
        self.block_data_mut(bb).is_cleanup = true;
        bb
    }

    pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
        debug!("push({:?}, {:?})", block, statement);
        self.block_data_mut(block).statements.push(statement);
    }

    pub fn push_assign(&mut self,
                       block: BasicBlock,
                       source_info: SourceInfo,
                       lvalue: &Lvalue<'tcx>,
                       rvalue: Rvalue<'tcx>) {
        self.push(block, Statement {
            source_info: source_info,
            kind: StatementKind::Assign(lvalue.clone(), rvalue)
        });
    }

    pub fn push_assign_constant(&mut self,
                                block: BasicBlock,
                                source_info: SourceInfo,
                                temp: &Lvalue<'tcx>,
                                constant: Constant<'tcx>) {
        self.push_assign(block, source_info, temp,
                         Rvalue::Use(Operand::Constant(constant)));
    }

    pub fn push_assign_unit(&mut self,
                            block: BasicBlock,
                            source_info: SourceInfo,
                            lvalue: &Lvalue<'tcx>) {
        self.push_assign(block, source_info, lvalue, Rvalue::Aggregate(
            AggregateKind::Tuple, vec![]
        ));
    }

    pub fn terminate(&mut self,
                     block: BasicBlock,
                     source_info: SourceInfo,
                     kind: TerminatorKind<'tcx>) {
        debug!("terminating block {:?} <- {:?}", block, kind);
        debug_assert!(self.block_data(block).terminator.is_none(),
                      "terminate: block {:?}={:?} already has a terminator set",
                      block,
                      self.block_data(block));
        self.block_data_mut(block).terminator = Some(Terminator {
            source_info: source_info,
            kind: kind,
        });
    }
}
<|endoftext|>


<commit_before>//! [PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid)

use ruma_api::ruma_api;
use ruma_events::{AnyMessageEventContent, EventContent as _};
use ruma_identifiers::{EventId, RoomId};
use ruma_serde::Raw;

ruma_api! {
    metadata: {
        description: "Send a message event to a room.",
        method: PUT,
        name: "create_message_event",
        path: "/_matrix/client/r0/rooms/:room_id/send/:event_type/:txn_id",
        rate_limited: false,
        authentication: AccessToken,
    }

    request: {
        /// The room to send the event to.
        #[ruma_api(path)]
        pub room_id: &'a RoomId,

        /// The transaction ID for this event.
        ///
        /// Clients should generate an ID unique across requests with the
        /// same access token; it will be used by the server to ensure
        /// idempotency of requests.
        #[ruma_api(path)]
        pub txn_id: &'a str,

        /// The type of event to send.
        #[ruma_api(path)]
        pub event_type: &'a str,

        /// The event content to send.
        #[ruma_api(body)]
        pub body: Raw<AnyMessageEventContent>,
    }

    response: {
        /// A unique identifier for the event.
        pub event_id: EventId,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given room id, transaction id and event content.
    pub fn new(room_id: &'a RoomId, txn_id: &'a str, content: &'a AnyMessageEventContent) -> Self {
        Self { room_id, txn_id, event_type: content.event_type(), body: content.into() }
    }

    /// Creates a new `Request` with the given room id, transaction id, event type and raw event
    /// content.
    pub fn new_raw(
        room_id: &'a RoomId,
        txn_id: &'a str,
        event_type: &'a str,
        body: Raw<AnyMessageEventContent>,
    ) -> Self {
        Self { room_id, txn_id, event_type, body }
    }
}

impl Response {
    /// Creates a new `Response` with the given event id.
    pub fn new(event_id: EventId) -> Self {
        Self { event_id }
    }
}
<commit_msg>client-api: Reorder send_message_event Request fields<commit_after>//! [PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid)

use ruma_api::ruma_api;
use ruma_events::{AnyMessageEventContent, EventContent as _};
use ruma_identifiers::{EventId, RoomId};
use ruma_serde::Raw;

ruma_api! {
    metadata: {
        description: "Send a message event to a room.",
        method: PUT,
        name: "create_message_event",
        path: "/_matrix/client/r0/rooms/:room_id/send/:event_type/:txn_id",
        rate_limited: false,
        authentication: AccessToken,
    }

    request: {
        /// The room to send the event to.
        #[ruma_api(path)]
        pub room_id: &'a RoomId,

        /// The type of event to send.
        #[ruma_api(path)]
        pub event_type: &'a str,

        /// The transaction ID for this event.
        ///
        /// Clients should generate an ID unique across requests with the
        /// same access token; it will be used by the server to ensure
        /// idempotency of requests.
        #[ruma_api(path)]
        pub txn_id: &'a str,

        /// The event content to send.
        #[ruma_api(body)]
        pub body: Raw<AnyMessageEventContent>,
    }

    response: {
        /// A unique identifier for the event.
        pub event_id: EventId,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given room id, transaction id and event content.
    pub fn new(room_id: &'a RoomId, txn_id: &'a str, content: &'a AnyMessageEventContent) -> Self {
        Self { room_id, txn_id, event_type: content.event_type(), body: content.into() }
    }

    /// Creates a new `Request` with the given room id, transaction id, event type and raw event
    /// content.
    pub fn new_raw(
        room_id: &'a RoomId,
        txn_id: &'a str,
        event_type: &'a str,
        body: Raw<AnyMessageEventContent>,
    ) -> Self {
        Self { room_id, txn_id, event_type, body }
    }
}

impl Response {
    /// Creates a new `Response` with the given event id.
    pub fn new(event_id: EventId) -> Self {
        Self { event_id }
    }
}
<|endoftext|>