<commit_before>use futures_01::{
    task as task01, Async as Async01, AsyncSink as AsyncSink01,
    Future as Future01, Poll as Poll01, Sink as Sink01,
    StartSend as StartSend01, Stream as Stream01,
};
use futures_core::{
    task as task03, TryFuture as TryFuture03, TryStream as TryStream03,
};
use futures_sink::Sink as Sink03;
use std::{marker::Unpin, pin::Pin, ptr::NonNull, sync::Arc};

/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture),
/// [`TryStream`](futures_core::stream::TryStream) or
/// [`Sink`](futures_sink::Sink) into a futures 0.1
/// [`Future`](futures::future::Future),
/// [`Stream`](futures::stream::Stream) or
/// [`Sink`](futures::sink::Sink).
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat<T> {
    pub(crate) inner: T,
}

impl<T> Compat<T> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`Compat`].
    pub(crate) fn new(inner: T) -> Compat<T> {
        Compat { inner }
    }
}

fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>)
    -> Result<Async01<T>, E>
{
    match x {
        task03::Poll::Ready(Ok(t)) => Ok(Async01::Ready(t)),
        task03::Poll::Pending => Ok(Async01::NotReady),
        task03::Poll::Ready(Err(e)) => Err(e),
    }
}

impl<Fut> Future01 for Compat<Fut>
where
    Fut: TryFuture03 + Unpin,
{
    type Item = Fut::Ok;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll01<Self::Item, Self::Error> {
        with_context(self, |inner, lw| poll_03_to_01(inner.try_poll(lw)))
    }
}

impl<St> Stream01 for Compat<St>
where
    St: TryStream03 + Unpin,
{
    type Item = St::Ok;
    type Error = St::Error;

    fn poll(&mut self) -> Poll01<Option<Self::Item>, Self::Error> {
        with_context(self, |inner, lw| match inner.try_poll_next(lw) {
            task03::Poll::Ready(None) => Ok(Async01::Ready(None)),
            task03::Poll::Ready(Some(Ok(t))) => Ok(Async01::Ready(Some(t))),
            task03::Poll::Pending => Ok(Async01::NotReady),
            task03::Poll::Ready(Some(Err(e))) => Err(e),
        })
    }
}

impl<T> Sink01 for Compat<T>
where
    T: Sink03 + Unpin,
{
    type SinkItem = T::SinkItem;
    type SinkError = T::SinkError;

    fn start_send(
        &mut self,
        item: Self::SinkItem,
    ) -> StartSend01<Self::SinkItem, Self::SinkError> {
        with_context(self, |mut inner, lw| {
            match inner.as_mut().poll_ready(lw) {
                task03::Poll::Ready(Ok(())) => {
                    inner.start_send(item).map(|()| AsyncSink01::Ready)
                }
                task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)),
                task03::Poll::Ready(Err(e)) => Err(e),
            }
        })
    }

    fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_flush(lw)))
    }

    fn close(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_close(lw)))
    }
}

struct Current(task01::Task);

impl Current {
    fn new() -> Current {
        Current(task01::current())
    }

    fn as_waker(&self) -> task03::LocalWaker {
        unsafe {
            task03::LocalWaker::new(NonNull::new_unchecked(self as *const Current as *mut Current))
        }
    }
}

unsafe impl task03::UnsafeWake for Current {
    #[inline]
    unsafe fn clone_raw(&self) -> task03::Waker {
        task03::Waker::from(Arc::new(Current(self.0.clone())))
    }

    #[inline]
    unsafe fn drop_raw(&self) {} // Does nothing

    #[inline]
    unsafe fn wake(&self) {
        self.0.notify();
    }
}

impl task03::Wake for Current {
    fn wake(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}

fn with_context<T, R, F>(compat: &mut Compat<T>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &task03::LocalWaker) -> R,
{
    let current = Current::new();
    let lw = current.as_waker();
    f(Pin::new(&mut compat.inner), &lw)
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>)
        -> Result<T, std::io::Error>
    {
        match x {
            task03::Poll::Ready(Ok(t)) => Ok(t),
            task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()),
            task03::Poll::Ready(Err(e)) => Err(e),
        }
    }

    impl<R: AsyncRead03> std::io::Read for Compat<R> {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_read(&lw, buf))
        }
    }

    impl<R: AsyncRead03> AsyncRead01 for Compat<R> {
        unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
            let initializer = self.inner.initializer();
            let does_init = initializer.should_initialize();
            if does_init {
                initializer.initialize(buf);
            }
            does_init
        }
    }

    impl<W: AsyncWrite03> std::io::Write for Compat<W> {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_write(&lw, buf))
        }

        fn flush(&mut self) -> std::io::Result<()> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_flush(&lw))
        }
    }

    impl<W: AsyncWrite03> AsyncWrite01 for Compat<W> {
        fn shutdown(&mut self) -> std::io::Result<Async01<()>> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_01(self.inner.poll_close(&lw))
        }
    }
}
<commit_msg>Make `Current` a bit safer to use by attaching a lifetime to the `LocalWaker`<commit_after>use futures_01::{
    task as task01, Async as Async01, AsyncSink as AsyncSink01,
    Future as Future01, Poll as Poll01, Sink as Sink01,
    StartSend as StartSend01, Stream as Stream01,
};
use futures_core::{
    task as task03, TryFuture as TryFuture03, TryStream as TryStream03,
};
use futures_sink::Sink as Sink03;
use std::{marker::{PhantomData, Unpin}, ops::Deref, pin::Pin, ptr::NonNull, sync::Arc};

/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture),
/// [`TryStream`](futures_core::stream::TryStream) or
/// [`Sink`](futures_sink::Sink) into a futures 0.1
/// [`Future`](futures::future::Future),
/// [`Stream`](futures::stream::Stream) or
/// [`Sink`](futures::sink::Sink).
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat<T> {
    pub(crate) inner: T,
}

impl<T> Compat<T> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`Compat`].
    pub(crate) fn new(inner: T) -> Compat<T> {
        Compat { inner }
    }
}

fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>)
    -> Result<Async01<T>, E>
{
    match x {
        task03::Poll::Ready(Ok(t)) => Ok(Async01::Ready(t)),
        task03::Poll::Pending => Ok(Async01::NotReady),
        task03::Poll::Ready(Err(e)) => Err(e),
    }
}

impl<Fut> Future01 for Compat<Fut>
where
    Fut: TryFuture03 + Unpin,
{
    type Item = Fut::Ok;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll01<Self::Item, Self::Error> {
        with_context(self, |inner, lw| poll_03_to_01(inner.try_poll(lw)))
    }
}

impl<St> Stream01 for Compat<St>
where
    St: TryStream03 + Unpin,
{
    type Item = St::Ok;
    type Error = St::Error;

    fn poll(&mut self) -> Poll01<Option<Self::Item>, Self::Error> {
        with_context(self, |inner, lw| match inner.try_poll_next(lw) {
            task03::Poll::Ready(None) => Ok(Async01::Ready(None)),
            task03::Poll::Ready(Some(Ok(t))) => Ok(Async01::Ready(Some(t))),
            task03::Poll::Pending => Ok(Async01::NotReady),
            task03::Poll::Ready(Some(Err(e))) => Err(e),
        })
    }
}

impl<T> Sink01 for Compat<T>
where
    T: Sink03 + Unpin,
{
    type SinkItem = T::SinkItem;
    type SinkError = T::SinkError;

    fn start_send(
        &mut self,
        item: Self::SinkItem,
    ) -> StartSend01<Self::SinkItem, Self::SinkError> {
        with_context(self, |mut inner, lw| {
            match inner.as_mut().poll_ready(lw) {
                task03::Poll::Ready(Ok(())) => {
                    inner.start_send(item).map(|()| AsyncSink01::Ready)
                }
                task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)),
                task03::Poll::Ready(Err(e)) => Err(e),
            }
        })
    }

    fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_flush(lw)))
    }

    fn close(&mut self) -> Poll01<(), Self::SinkError> {
        with_context(self, |inner, lw| poll_03_to_01(inner.poll_close(lw)))
    }
}

// `task::LocalWaker` with a lifetime tied to it.
struct LocalWakerLt<'a> {
    inner: task03::LocalWaker,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Deref for LocalWakerLt<'a> {
    type Target = task03::LocalWaker;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

struct Current(task01::Task);

impl Current {
    fn new() -> Current {
        Current(task01::current())
    }

    fn as_waker(&self) -> LocalWakerLt {
        unsafe {
            LocalWakerLt {
                inner: task03::LocalWaker::new(NonNull::new_unchecked(self as *const Current as *mut Current)),
                _marker: PhantomData,
            }
        }
    }
}

unsafe impl task03::UnsafeWake for Current {
    #[inline]
    unsafe fn clone_raw(&self) -> task03::Waker {
        task03::Waker::from(Arc::new(Current(self.0.clone())))
    }

    #[inline]
    unsafe fn drop_raw(&self) {} // Does nothing

    #[inline]
    unsafe fn wake(&self) {
        self.0.notify();
    }
}

impl task03::Wake for Current {
    fn wake(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}

fn with_context<T, R, F>(compat: &mut Compat<T>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &task03::LocalWaker) -> R,
{
    let current = Current::new();
    let lw = current.as_waker();
    f(Pin::new(&mut compat.inner), &lw)
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>)
        -> Result<T, std::io::Error>
    {
        match x {
            task03::Poll::Ready(Ok(t)) => Ok(t),
            task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()),
            task03::Poll::Ready(Err(e)) => Err(e),
        }
    }

    impl<R: AsyncRead03> std::io::Read for Compat<R> {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_read(&lw, buf))
        }
    }

    impl<R: AsyncRead03> AsyncRead01 for Compat<R> {
        unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
            let initializer = self.inner.initializer();
            let does_init = initializer.should_initialize();
            if does_init {
                initializer.initialize(buf);
            }
            does_init
        }
    }

    impl<W: AsyncWrite03> std::io::Write for Compat<W> {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_write(&lw, buf))
        }

        fn flush(&mut self) -> std::io::Result<()> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_io(self.inner.poll_flush(&lw))
        }
    }

    impl<W: AsyncWrite03> AsyncWrite01 for Compat<W> {
        fn shutdown(&mut self) -> std::io::Result<Async01<()>> {
            let current = Current::new();
            let lw = current.as_waker();
            poll_03_to_01(self.inner.poll_close(&lw))
        }
    }
}
<|endoftext|>


<commit_before>//! Module that contains a crawler function that crawls through the vulkan xml and returns a
//! Registry struct
use xml::reader::{Events, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;
use std::io::Read;
use std::ffi::CStr;
use {VkRegistry, VkType, VkMember};
use VkVariant;

pub fn crawl<R: Read>(xml_events: Events<R>, mut registry: VkRegistry) -> VkRegistry {
    use self::XmlElement::*;

    let mut type_buffer = VkType::Unhandled;
    let mut cur_block = VkBlock::None;
    // A variable that contains what the index of the element in vk_elements that vk_elements was
    // popped to. Used to prevent the element iterator from going over elements that have already
    // been checked.
    let mut popped_to = 0;

    // A stack of the relevant elements in the vulkan xml
    let mut vk_elements = Vec::with_capacity(10);

    for event in xml_events {

        let event = event.unwrap();
        match event {
            XmlEvent::StartElement{ name, attributes, .. } => {
                vk_elements.push(XmlElement::new_tag(name, attributes));
            }

            XmlEvent::EndElement{ name } => {
                for el in &vk_elements[popped_to..] {
                    match *el {
                        Tag{name: ref tag_name, attributes: ref tag_attrs} =>
                            match &tag_name[..] {
                                "types"      => cur_block = VkBlock::Types,
                                "enums"      => cur_block = VkBlock::Enums,
                                "commands"   => cur_block = VkBlock::Commands,
                                "extensions" => cur_block = VkBlock::Extensions,

                                "type"  =>
                                    if VkBlock::Types == cur_block {
                                        if let Some(category) = find_attribute(tag_attrs, "category") {
                                            registry.push_type(type_buffer).ok();
                                            match category {
                                                "basetype"      => type_buffer = VkType::Unhandled,
                                                "bitmask"       => type_buffer = VkType::Unhandled,
                                                "define"        => type_buffer = VkType::Unhandled,
                                                "enum"          => type_buffer = VkType::Unhandled,
                                                "funcpointer"   => type_buffer = VkType::Unhandled,
                                                "group"         => type_buffer = VkType::Unhandled,
                                                "handle"        => type_buffer = VkType::Unhandled,
                                                "include"       => type_buffer = VkType::Unhandled,
                                                "struct"        =>
                                                    type_buffer = VkType::Struct{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), fields: Vec::with_capacity(8)},
                                                "union"         =>
                                                    type_buffer = VkType::Union{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), variants: Vec::with_capacity(8)},
                                                _               => panic!("Unexpected category")
                                            }
                                        }
                                    } else {/*panic!("\"type\" tag found outside of \"types\" block")*/}, //TODO: implement fully so panic can be used

                                "member" =>
                                    if VkBlock::Types == cur_block {
                                        match type_buffer {
                                            VkType::Struct{ref mut fields, ..} => fields.push(VkMember::empty()),
                                            VkType::Union{ref mut variants, ..} => variants.push(VkMember::empty()),
                                            _ =>
                                                panic!("Unexpected \"member\" tag found")
                                        }
                                    } else {panic!("\"member\" tag found outside of \"types\" block")},

                                _ => ()
                            },

                        Characters{ref chars, tag} => {
                            let chars = &chars[..];
                            if VkBlock::Types == cur_block {
                                match type_buffer {
                                    VkType::Struct{fields: ref mut members, ..} |
                                    VkType::Union{variants: ref mut members, ..} =>
                                        match tag {
                                            "member" =>
                                                match chars {
                                                    "const" => members.last_mut().unwrap().change_type_const(),
                                                    "*"     => members.last_mut().unwrap().change_type_ptr(),
                                                    _
                                                        if &chars[0..1] == "[" =>
                                                        match parse_array_index(chars) {
                                                            Some((size, _)) => {members.last_mut().unwrap().change_type_array(size);}
                                                            None => panic!(format!("Unexpected characters after name: {}", chars))
                                                        },
                                                    _ => ()
                                                },
                                            "type" =>
                                                members.last_mut().unwrap().set_type(registry.append_str(chars)),
                                            "name" =>
                                                if let Some((size, name_len)) = parse_array_index(chars) {
                                                    members.last_mut().unwrap().change_type_array(size)
                                                                               .set_name(registry.append_str(&chars[..name_len]))
                                                } else {members.last_mut().unwrap().set_name(registry.append_str(chars))},
                                            "enum" =>
                                                members.last_mut().unwrap().change_type_array_enum(registry.append_str(chars)),
                                            _ => ()
                                        },
                                    _ => ()
                                }
                            }
                        }
                    }
                }

                pop_element_stack(&mut vk_elements);
                popped_to = vk_elements.len();
            }

            XmlEvent::Characters(chars) => {
                let tag_ptr =
                    match *vk_elements.last().unwrap() {
                        XmlElement::Tag{name: ref tag, ..} => &tag[..] as *const str,
                        // In circumstances where the xml reads something like <foo>foostart<bar>bar</bar>fooend</foo>, the
                        // "fooend" string will appear in vk_elements after the "foostart" event, instead of after <foo>.
                        // Because of that, we must pull the tag from the other Characters event.
                        XmlElement::Characters{tag, ..} => tag as *const str
                    };

                unsafe{ vk_elements.push(XmlElement::new_chars(chars, &*tag_ptr)) }
            }

            _ => ()
        }
    }

    for t in &registry.types {
        unsafe {
            match *t {
                VkType::Struct{name, ref fields} => {
                    println!("Struct {:?}", CStr::from_ptr(name));

                    for f in fields {
                        println!("\t{:?}", f);
                    }
                }
                VkType::Union{name, ref variants} => {
                    println!("Union {:?}", CStr::from_ptr(name));

                    for v in variants {
                        println!("\t{:?}", v);
                    }
                }
                _ => ()
            }
        }
    }

    registry
}

fn find_attribute<'v>(source: &'v Vec<OwnedAttribute>, query: &str) -> Option<&'v str> {
    source.into_iter().skip_while(|attr| &attr.name.local_name != query).next().map(|res| &*res.value)
}

/// Takes a mutable reference to a XmlElement stack, popping the stack of Character elements until
/// it pops a Tag
fn pop_element_stack(vk_elements: &mut Vec<XmlElement>) {
    match vk_elements.pop() {
        Some(el) =>
            if let XmlElement::Characters{..} = el {
                pop_element_stack(vk_elements)
            },

        None => panic!("Invalid xml; Unexpected closing tag")
    }
}

/// Takes a string slice and extracts x from [x], as long as [x] is at the end.
///
///
/// Returns (x, length of `chars` without [x]) if "[x]" is detected
///
/// Returns (0, 0) if "[" is detected
fn parse_array_index(chars: &str) -> Option<(usize, usize)> {
    let mut chariter = chars.chars().rev();
    match chariter.next().unwrap() {
        // This only occurs when the variable is going to be an array. Now, in most cases it appears
        // *outside* of <name>, but some dumbass decided to have two fields in the entire xml contain it
        // inside. To the person who did that (you know who you are): if you're writing a document designed
        // to be easy to parse, PLEASE keep it consistent. This goes for everyone else as well - think of
        // the person that has to write an interpreter for your goddamn file.
        ']' => {
            // The size of the array
            let mut size = 0;
            for (i, digit) in chariter.clone().take_while(|c| c.is_digit(10)).enumerate() {
                size += digit.to_digit(10).unwrap() as usize * (10usize.pow(i as u32));
            }

            // The length of the actual name, dropping the array length. Is decremented in the iterator below.
            let mut name_len = chars.len()-1;
            match chariter.skip_while(|c| {
                                    name_len -= 1;
                                    c.is_digit(10) | c.is_whitespace()}).next() {
                Some('[') => (),
                Some(c)   => panic!(format!("Expected '['; found '{}'", c)),
                None      => panic!("Expected '['; found nothing")
            }
            Some((size, name_len))
        }
        '[' => Some((0, 0)),
        _   =>  None
    }
}

#[derive(Debug)]
enum XmlElement<'a> {
    Tag {
        /// The name of the tag e.g. "hello" in <hello>
        name: String,
        /// The attributes contained within the specification xml.
        attributes: Vec<OwnedAttribute>
    },
    Characters{
        chars: String,
        tag: &'a str
    }
}

impl<'a> XmlElement<'a> {
    fn new_tag(name: OwnedName, attributes: Vec<OwnedAttribute>) -> XmlElement<'a> {
        XmlElement::Tag {
            name: name.local_name,
            attributes: attributes
        }
    }

    fn new_chars(chars: String, tag: &'a str) -> XmlElement<'a> {
        XmlElement::Characters {
            chars: chars,
            tag: tag
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
enum VkBlock {
    Types,
    Enums,
    Commands,
    Extensions,
    None
}<commit_msg>Re-styled crawler.rs<commit_after>//! Module that contains a crawler function that crawls through the vulkan xml and returns a
//! Registry struct
use xml::reader::{Events, XmlEvent};
use xml::name::OwnedName;
use xml::attribute::OwnedAttribute;
use std::io::Read;
use std::ffi::CStr;
use {VkRegistry, VkType, VkMember};
use VkVariant;

pub fn crawl<R: Read>(xml_events: Events<R>, mut registry: VkRegistry) -> VkRegistry {
    use self::XmlElement::*;

    let mut type_buffer = VkType::Unhandled;
    let mut cur_block = VkBlock::None;
    // A variable that contains what the index of the element in vk_elements that vk_elements was
    // popped to. Used to prevent the element iterator from going over elements that have already
    // been checked.
    let mut popped_to = 0;

    // A stack of the relevant elements in the vulkan xml
    let mut vk_elements = Vec::with_capacity(10);

    for event in xml_events {

        let event = event.unwrap();
        match event {
            XmlEvent::StartElement{ name, attributes, .. } => {
                vk_elements.push(XmlElement::new_tag(name, attributes));
            }

            XmlEvent::EndElement{ name } => {
                for el in &vk_elements[popped_to..] {
                    match *el {
                        Tag{name: ref tag_name, attributes: ref tag_attrs} =>
                            match &tag_name[..] {
                                "types"      => cur_block = VkBlock::Types,
                                "enums"      => cur_block = VkBlock::Enums,
                                "commands"   => cur_block = VkBlock::Commands,
                                "extensions" => cur_block = VkBlock::Extensions,

                                "type"
                                    if VkBlock::Types == cur_block =>
                                    if let Some(category) = find_attribute(tag_attrs, "category") {
                                        registry.push_type(type_buffer).ok();
                                        match category {
                                            "basetype"      => type_buffer = VkType::Unhandled,
                                            "bitmask"       => type_buffer = VkType::Unhandled,
                                            "define"        => type_buffer = VkType::Unhandled,
                                            "enum"          => type_buffer = VkType::Unhandled,
                                            "funcpointer"   => type_buffer = VkType::Unhandled,
                                            "group"         => type_buffer = VkType::Unhandled,
                                            "handle"        => type_buffer = VkType::Unhandled,
                                            "include"       => type_buffer = VkType::Unhandled,
                                            "struct"        =>
                                                type_buffer = VkType::Struct{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), fields: Vec::with_capacity(8)},
                                            "union"         =>
                                                type_buffer = VkType::Union{name: registry.append_str(find_attribute(tag_attrs, "name").unwrap()), variants: Vec::with_capacity(8)},
                                            _               => panic!("Unexpected category")
                                        }
                                    },
                                "type"       => (),

                                "member"
                                    if VkBlock::Types == cur_block =>
                                    match type_buffer {
                                        VkType::Struct{fields: ref mut members, ..}   |
                                        VkType::Union{variants: ref mut members, ..} => variants.push(VkMember::empty()),
                                        _                                            => panic!("Unexpected \"member\" tag found")
                                    },
                                "member"     => panic!("\"member\" tag found outside of \"types\" block"),

                                _ => ()
                            },

                        Characters{ref chars, tag}
                            if VkBlock::Types == cur_block => {
                            let chars = &chars[..];
                            match type_buffer {
                                VkType::Struct{fields: ref mut members, ..} |
                                VkType::Union{variants: ref mut members, ..} =>
                                    match tag {
                                        "member" =>
                                            match chars {
                                                "const" => members.last_mut().unwrap().change_type_const(),
                                                "*"     => members.last_mut().unwrap().change_type_ptr(),
                                                _
                                                    if &chars[0..1] == "[" =>
                                                    match parse_array_index(chars) {
                                                        Some((size, _)) => {members.last_mut().unwrap().change_type_array(size);}
                                                        None => panic!(format!("Unexpected characters after name: {}", chars))
                                                    },
                                                _       => ()
                                            },
                                        "type"   => members.last_mut().unwrap().set_type(registry.append_str(chars)),
                                        "name"   =>
                                            if let Some((size, name_len)) = parse_array_index(chars) {
                                                members.last_mut().unwrap().change_type_array(size)
                                                                           .set_name(registry.append_str(&chars[..name_len]))
                                            } else {members.last_mut().unwrap().set_name(registry.append_str(chars))},
                                        "enum"   => members.last_mut().unwrap().change_type_array_enum(registry.append_str(chars)),
                                        _        => ()
                                    },
                                _ => ()
                            }
                        }
                        Characters{..} => ()
                    }
                }

                pop_element_stack(&mut vk_elements);
                popped_to = vk_elements.len();
            }

            XmlEvent::Characters(chars) => {
                let tag_ptr =
                    match *vk_elements.last().unwrap() {
                        XmlElement::Tag{name: ref tag, ..} => &tag[..] as *const str,
                        // In circumstances where the xml reads something like <foo>foostart<bar>bar</bar>fooend</foo>, the
                        // "fooend" string will appear in vk_elements after the "foostart" event, instead of after <foo>.
                        // Because of that, we must pull the tag from the other Characters event.
                        XmlElement::Characters{tag, ..}    => tag as *const str
                    };

                unsafe{ vk_elements.push(XmlElement::new_chars(chars, &*tag_ptr)) }
            }

            _ => ()
        }
    }

    for t in &registry.types {
        unsafe {
            match *t {
                VkType::Struct{name, ref fields}  => {
                    println!("Struct {:?}", CStr::from_ptr(name));
                    for f in fields {
                        println!("\t{:?}", f);
                    }
                }
                VkType::Union{name, ref variants} => {
                    println!("Union {:?}", CStr::from_ptr(name));
                    for v in variants {
                        println!("\t{:?}", v);
                    }
                }
                _ => ()
            }
        }
    }

    registry
}

fn find_attribute<'v>(source: &'v Vec<OwnedAttribute>, query: &str) -> Option<&'v str> {
    source.into_iter().skip_while(|attr| &attr.name.local_name != query).next().map(|res| &*res.value)
}

/// Takes a mutable reference to a XmlElement stack, popping the stack of Character elements until
/// it pops a Tag
fn pop_element_stack(vk_elements: &mut Vec<XmlElement>) {
    if let Some(el) = vk_elements.pop() {
        if let XmlElement::Characters{..} = el {
            pop_element_stack(vk_elements)
        }
    } else {panic!("Invalid xml; Unexpected closing tag")}
}

/// Takes a string slice and extracts x from [x], as long as [x] is at the end.
///
///
/// Returns (x, length of `chars` without [x]) if "[x]" is detected
///
/// Returns (0, 0) if "[" is detected
fn parse_array_index(chars: &str) -> Option<(usize, usize)> {
    let mut chariter = chars.chars().rev();
    match chariter.next().unwrap() {
        // This only occurs when the variable is going to be an array. Now, in most cases it appears
        // *outside* of <name>, but some dumbass decided to have two fields in the entire xml contain it
        // inside. To the person who did that (you know who you are): if you're writing a document designed
        // to be easy to parse, PLEASE keep it consistent. This goes for everyone else as well - think of
        // the person that has to write an interpreter for your goddamn file.
        ']' => {
            // The size of the array
            let mut size = 0;
            for (i, digit) in chariter.clone().take_while(|c| c.is_digit(10)).enumerate() {
                size += digit.to_digit(10).unwrap() as usize * (10usize.pow(i as u32));
            }

            // The length of the actual name, dropping the array length. Is decremented in the iterator below.
            let mut name_len = chars.len()-1;
            match chariter.skip_while(|c| {name_len -= 1;
                                           c.is_digit(10) | c.is_whitespace()}
                                           ).next() {
                Some('[') => (),
                Some(c)   => panic!(format!("Expected '['; found '{}'", c)),
                None      => panic!("Expected '['; found nothing")
            }
            Some((size, name_len))
        }
        '[' => Some((0, 0)),
        _   => None
    }
}

#[derive(Debug)]
enum XmlElement<'a> {
    Tag {
        /// The name of the tag e.g. "hello" in <hello>
        name: String,
        /// The attributes contained within the specification xml.
        attributes: Vec<OwnedAttribute>
    },
    Characters{
        chars: String,
        tag: &'a str
    }
}

impl<'a> XmlElement<'a> {
    fn new_tag(name: OwnedName, attributes: Vec<OwnedAttribute>) -> XmlElement<'a> {
        XmlElement::Tag {
            name: name.local_name,
            attributes: attributes
        }
    }

    fn new_chars(chars: String, tag: &'a str) -> XmlElement<'a> {
        XmlElement::Characters {
            chars: chars,
            tag: tag
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
enum VkBlock {
    Types,
    Enums,
    Commands,
    Extensions,
    None
}<|endoftext|>


<commit_before>// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};
use std::io::buffered::BufferedReader;
use std::io::File;

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut count: int = 0;

fn main() {

    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {

        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let mut line1 = "";

            for str in request_str.split('\n'){ // get the first line
                line1 = str.clone();
                break;
            }

            let mut path = "";
            println(line1);

            let temp: ~[&str] = line1.split(' ').collect();
            path = temp[1].clone(); // this gets the path

            let file_content = readFile(path);

            unsafe {    // so we can increment count 'illegally'

            count += 1;

            if file_content == ~"index" {

                let index: ~str = format!(
                    "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                     <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty! Total hits = {:d}

                     \r\n", count);

                stream.write(index.as_bytes());
                println!("Connection terminates");
            }

            else {
                let response: ~str = format!("{:s}", file_content);

                stream.write(response.as_bytes());
                println!("Connection terminates");
        }

            }
        }
    }
}

fn readFile(x: &str) -> ~str {

    let y = x.slice_from(1).clone(); // get rid of leading '/'
    let x = y.trim().clone();

    if x == "" {
        return ~"index";
    }

    let mut html = false;
    let mut in_dir = false;

    //testing to see if looking in same directory/if its an HTML file
    let mut temp: ~[&str] = y.split('/').collect();

    if temp[0] != ""{
        in_dir = true;
    }

    temp = y.split('.').collect();
    if temp[temp.len()-1] == "html"{
        html = true;
    }

    println!("{} {}", in_dir, html);

    let path = Path::new(y);

    match (path.exists(), path.is_file(), html, in_dir){

        (true,true, true, true) => {

            match File::open(&Path::new(path)) {

                Some(file) => {
                    let mut reader = BufferedReader::new(file);
                    let input = reader.read_to_str();
                    return input;

                }

                None =>{~"HTTP/1.1 500 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 500 ERROR

 Something really bad happened, lo siento
"}
            }

        }
        (true,true,_,false) => {~"HTTP/1.1 403 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 403 ERROR

 Unauthorized access!
"}

        (true,true,false,_) => {~"HTTP/1.1 403 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 403 ERROR

 Unauthorized access!
"}

        (_,_,_,_) => {~"HTTP/1.1 404 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 404 ERROR

 Page not found
"}
    }
}<commit_msg>Removed testing println's from zhttpto.re<commit_after>// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};
use std::io::buffered::BufferedReader;
use std::io::File;

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut count: int = 0;

fn main() {

    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {

        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let mut line1 = "";

            for str in request_str.split('\n'){ // get the first line
                line1 = str.clone();
                break;
            }

            let mut path = "";

            let temp: ~[&str] = line1.split(' ').collect();
            path = temp[1].clone(); // this gets the path

            let file_content = readFile(path);

            unsafe {    // so we can increment count 'illegally'

            count += 1;

            if file_content == ~"index" {

                let index: ~str = format!(
                    "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                     <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty! Total hits = {:d}

                     \r\n", count);

                stream.write(index.as_bytes());
                println!("Connection terminates");
            }

            else {
                let response: ~str = format!("{:s}", file_content);

                stream.write(response.as_bytes());
                println!("Connection terminates");
        }

            }
        }
    }
}

fn readFile(x: &str) -> ~str {

    let mut y = x.slice_from(1).clone();
    let z = x.slice(0,1).clone();
    println(z);
    if z != "/" {
        y = x.clone();
    }

    let x = y.trim().clone();

    if x == "" {
        return ~"index";
    }

    let mut html = false;
    let mut in_dir = false;

    //testing to see if looking in allowed directory/if its an HTML file
    let mut temp: ~[&str] = y.split('/').collect();

    if temp[0] != "" && temp[0] != ".." {
        in_dir = true;
    }

    temp = y.split('.').collect();
    if temp[temp.len()-1] == "html"{
        html = true;
    }

    let path = Path::new(y);

    match (path.exists(), path.is_file(), html, in_dir){

        (true,true, true, true) => {

            match File::open(&Path::new(path)) {

                Some(file) => {
                    let mut reader = BufferedReader::new(file);
                    let input = reader.read_to_str();
                    return input;

                }

                None =>{~"HTTP/1.1 500 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 500 ERROR

 Something really bad happened, lo siento
"}
            }

        }
        (true,true,_,false) => {~"HTTP/1.1 403 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 403 ERROR

 Unauthorized access!
"}

        (true,true,false,_) => {~"HTTP/1.1 403 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 403 ERROR

 Unauthorized access!
"}

        (_,_,_,_) => {~"HTTP/1.1 404 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n

 404 ERROR

 Page not found
"}
    }
}
<|endoftext|>


<commit_before>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        flags.push("-Astable-features".to_owned());
    } else {
        flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    // Add a test env var to do environment communication tests
    std::env::set_var("MIRI_ENV_VAR_TEST", "0");

    run_pass_miri(false);
    // FIXME: hashmap ICEs with optimizations run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<commit_msg>Re-enable run-pass tests with optimizations enabled<commit_after>#![feature(custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec<String>) {
    let in_rustc_test_suite = rustc_test_suite().is_some();
    // Add some flags we always want.
    flags.push("--edition 2018".to_owned());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        flags.push("-Astable-features".to_owned());
    } else {
        flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    }
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        flags.push(format!("--sysroot {}", sysroot));
    }

    // The rest of the configuration.
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if in_rustc_test_suite {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    run_tests("compile-fail", path, target, flags);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    run_tests("ui", path, target, flags);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    // Add a test env var to do environment communication tests
    std::env::set_var("MIRI_ENV_VAR_TEST", "0");

    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<|endoftext|>


<commit_before>use serde_json::{from_slice, Value};

use super::super::request::BufferedHttpResponse;

#[derive(Deserialize)]
struct RawError {
    #[serde(rename = "__type", default)]
    typ: Option<String>,
    #[serde(default)]
    message: Option<String>
}

pub struct Error {
    pub typ: String,
    pub msg: String
}

impl Error {
    pub fn parse(res: &BufferedHttpResponse) -> Option<Error> {
        if let Ok(raw_err) = from_slice::<RawError>(&res.body) {
            let raw_error_type = raw_err.typ.unwrap_or_else(|| "Unknown".to_owned());
            let msg = raw_err.message.unwrap_or(String::new());

            let pieces: Vec<&str> = raw_error_type.split("#").collect();
            let typ = pieces.last().expect("Expected error type");

            Some(Error {typ: typ.to_string(), msg})
        } else {
            None
        }
    }

    // see boto RestJSONParser impl for parsing errors
    // https://github.com/boto/botocore/blob/4dff78c840403d1d17db9b3f800b20d3bd9fbf9f/botocore/parsers.py#L838-L850
    pub fn parse_rest(res: &BufferedHttpResponse) -> Option<Error> {
        if let Ok(json) = from_slice::<Value>(&res.body) {
            let typ = match res.headers.get("x-amzn-errortype") {
                Some(raw_error_type) => {
                    raw_error_type.split(':').next().unwrap_or_else(|| "Unknown")
                },
                _ => json.get("code").or_else(|| json.get("Code")).and_then(|c| c.as_str()).unwrap_or("Unknown")
            };

            // message can come in either \"message\" or \"Message\"
            // see boto BaseJSONParser impl for parsing message
            // https://github.com/boto/botocore/blob/4dff78c840403d1d17db9b3f800b20d3bd9fbf9f/botocore/parsers.py#L595-L598
            let msg = json.get("message").or_else(|| json.get("Message")).and_then(|m| m.as_str()).unwrap_or("").to_string();

            Some(Error {typ: typ.to_string(), msg})
        } else {
            None
        }
    }
}

#[test]
fn deserialize_dynamodb_error() {
    use hyper::StatusCode;
    use super::super::request::Headers;

    let payload = r#"{"__type":"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",
"message":"Requested resource not found: Table: tablename not found"}"#;
    let response = BufferedHttpResponse{
        status: StatusCode::OK,
        body: payload.into(),
        headers: Headers::default()
    };

    let error = Error::parse(&response).unwrap();

    assert_eq!(error.error_type, "ResourceNotFoundException");
    assert_eq!(error.error_message, "Requested resource not found: Table: tablename not found");
}
<commit_msg>fix core tests for json error decoding<commit_after>use serde_json::{from_slice, Value};

use super::super::request::BufferedHttpResponse;

#[derive(Deserialize)]
struct RawError {
    #[serde(rename = "__type", default)]
    typ: Option<String>,
    #[serde(default)]
    message: Option<String>
}

pub struct Error {
    pub typ: String,
    pub msg: String
}

impl Error {
    pub fn parse(res: &BufferedHttpResponse) -> Option<Error> {
        if let Ok(raw_err) = from_slice::<RawError>(&res.body) {
            let raw_error_type = raw_err.typ.unwrap_or_else(|| "Unknown".to_owned());
            let msg = raw_err.message.unwrap_or(String::new());

            let pieces: Vec<&str> = raw_error_type.split("#").collect();
            let typ = pieces.last().expect("Expected error type");

            Some(Error {typ: typ.to_string(), msg})
        } else {
            None
        }
    }

    // see boto RestJSONParser impl for parsing errors
    // https://github.com/boto/botocore/blob/4dff78c840403d1d17db9b3f800b20d3bd9fbf9f/botocore/parsers.py#L838-L850
    pub fn parse_rest(res: &BufferedHttpResponse) -> Option<Error> {
        if let Ok(json) = from_slice::<Value>(&res.body) {
            let typ = match res.headers.get("x-amzn-errortype") {
                Some(raw_error_type) => {
                    raw_error_type.split(':').next().unwrap_or_else(|| "Unknown")
                },
                _ => json.get("code").or_else(|| json.get("Code")).and_then(|c| c.as_str()).unwrap_or("Unknown")
            };

            // message can come in either \"message\" or \"Message\"
            // see boto BaseJSONParser impl for parsing message
            // https://github.com/boto/botocore/blob/4dff78c840403d1d17db9b3f800b20d3bd9fbf9f/botocore/parsers.py#L595-L598
            let msg = json.get("message").or_else(|| json.get("Message")).and_then(|m| m.as_str()).unwrap_or("").to_string();

            Some(Error {typ: typ.to_string(), msg})
        } else {
            None
        }
    }
}

#[test]
fn deserialize_dynamodb_error() {
    use hyper::StatusCode;
    use super::super::request::Headers;

    let payload = r#"{"__type":"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",
"message":"Requested resource not found: Table: tablename not found"}"#;
    let response = BufferedHttpResponse{
        status: StatusCode::OK,
        body: payload.into(),
        headers: Headers::default()
    };

    let error = Error::parse(&response).unwrap();

    assert_eq!(error.typ, "ResourceNotFoundException");
    assert_eq!(error.msg, "Requested resource not found: Table: tablename not found");
}
<|endoftext|>


<commit_before>extern crate wechat;

use wechat::WeChatClient;

static APPID: &'static str = "wxd7aa56e2c7b1f4f1";
static SECRET: &'static str = "2817b66a1d5829847196cf2f96ab2816";

#[test]
fn test_fetch_access_token() {
    let mut client = WeChatClient::new(APPID, SECRET);
    let access_token = client.fetch_access_token();
    assert!(access_token.is_some());
    assert!(!client.access_token.is_empty());
}

#[test]
fn test_call_api_with_no_access_token_provided() {
    let mut client = WeChatClient::new(APPID, SECRET);
    let res = client.get("getcallbackip", vec![]);
    let data = match res {
        Ok(data) => data,
        Err(_) => { panic!("Error calling API"); },
    };
    let ip_list = data.find("ip_list").unwrap();
    let ips = ip_list.as_array().unwrap();
    assert!(ips.len() > 0);
}<commit_msg>Use const instead of static for global constants<commit_after>extern crate wechat;

use wechat::WeChatClient;

const APPID: &'static str = "wxd7aa56e2c7b1f4f1";
const SECRET: &'static str = "2817b66a1d5829847196cf2f96ab2816";

#[test]
fn test_fetch_access_token() {
    let mut client = WeChatClient::new(APPID, SECRET);
    let access_token = client.fetch_access_token();
    assert!(access_token.is_some());
    assert!(!client.access_token.is_empty());
}

#[test]
fn test_call_api_with_no_access_token_provided() {
    let mut client = WeChatClient::new(APPID, SECRET);
    let res = client.get("getcallbackip", vec![]);
    let data = match res {
        Ok(data) => data,
        Err(_) => { panic!("Error calling API"); },
    };
    let ip_list = data.find("ip_list").unwrap();
    let ips = ip_list.as_array().unwrap();
    assert!(ips.len() > 0);
}<|endoftext|>


<commit_before>#![feature(macro_rules)]
extern crate string_telephone;

use string_telephone::{ConnectionConfig, ClientConnectionConfig, Client, Packet, PollEmpty};

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::io::Timer;
use std::time::duration::Duration;

fn deserializer(message: &Vec<u8>) -> Option<Vec<u8>> {
    Some(message.clone())
}

fn serializer(packet: &Vec<u8>) -> Vec<u8> {
    packet.clone()
}

fn generate_settings(port: u16, protocol_id: u32) -> (SocketAddr, SocketAddr, ConnectionConfig<Vec<u8>>, ClientConnectionConfig) {
    let my_addr = SocketAddr{ ip: Ipv4Addr(0, 0, 0, 0), port: 0 };
    let target_addr = SocketAddr{ ip: Ipv4Addr(127, 0, 0, 1), port: port };
    let settings = ConnectionConfig::new(protocol_id, 10, deserializer, serializer);
    let client_settings = ClientConnectionConfig::new(1, Duration::seconds(1));
    (my_addr, target_addr, settings, client_settings)
}

fn get_message(socket: &mut UdpSocket) -> (Vec<u8>, SocketAddr) {
    let mut buf = [0, ..255];
    match socket.recv_from(buf) {
        Ok((amt, src)) => (buf.slice_to(amt).to_owned(), src),
        Err(e) => fail!("Socket didn't get a message")
    }
}

macro_rules! with_bound_socket(
    ($socket:ident, ($variable:ident)$code:block) => (
        spawn(proc() {
            match UdpSocket::bind($socket) {
                Ok(mut $variable) => $code,
                Err(e) => fail!(e)
            }
        });
    )
)

/**
 * Test when there isn't a backend to connect to
 * Connect should return an IOResult stating we can't get there
 */
#[test]
fn connection_ignored() {
    let port = 65000;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Reported connected when there is no server!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * Test a normal connection where the backend replies with an accept
 */
#[test]
fn standard_connection() {

    let port = 65001;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(client) => {
            //Success!
        },
        Err(e) => fail!(e)
    };
}

/**
 * If the server gives us back a different protocol id, we shouldn't accept it
 */
#[test]
fn connection_different_protocol_id() {
    let port = 65002;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(122).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server with a different protocol ID!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * If the server specifically rejects us, we should give up
 */
#[test]
fn connection_rejected() {
    let port = 65003;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::reject(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server that rejected us!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * We should be able to specify how many retries we want
 */
#[test]
fn different_retry_count() {
    let port = 65004;
    let (my_addr, target_addr, settings, mut client_settings) = generate_settings(port, 121);
    client_settings.max_connect_retries = 3;

    let (tx, rx) = channel();
    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let mut attempts = 0u8;
        while attempts < 3 {
            get_message(&mut socket);
            attempts += 1;
        }

        tx.send(attempts);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => (),
        Err(_) => ()
    };

    assert!(rx.recv() == 3);
}

//TODO: Find a sensible way of testing timeout lengths

/**
 * We should instantly return when polling and there's no data available
 */
#[test]
fn empty_polling() {
    let port = 65005;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            assert!(match client.poll() { Err(PollEmpty) => true, _ => false});
        },
        Err(e) => fail!(e)
    };
}

/**
 * We should return an item if there's one there
 */
#[test]
fn single_item_polling() {
    let port = 65006;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //May have to wait a bit
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            match client.poll() {
                Ok(packet) => {
                    assert!(packet == vec![1]);
                },
                Err(e) => fail!("Couldn't match a polled message! - {}", e)
            };
        },
        Err(e) => fail!(e)
    };
}

#[test]
fn multiple_item_polling() {
    unimplemented!();
}

#[test]
fn ignore_bad_queue_items_polling() {
    unimplemented!();
}

#[test]
fn disconnection() {
    unimplemented!();
}

#[test]
fn timeout() {
    unimplemented!();
}

#[test]
fn send_correct_handshake() {
    unimplemented!();
}

#[test]
fn send_data() {
    unimplemented!();
}
<commit_msg>Multiple poll test<commit_after>#![feature(macro_rules)]
extern crate string_telephone;

use string_telephone::{ConnectionConfig, ClientConnectionConfig, Client, Packet, PollEmpty};

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::io::Timer;
use std::time::duration::Duration;

fn deserializer(message: &Vec<u8>) -> Option<Vec<u8>> {
    Some(message.clone())
}

fn serializer(packet: &Vec<u8>) -> Vec<u8> {
    packet.clone()
}

fn generate_settings(port: u16, protocol_id: u32) -> (SocketAddr, SocketAddr, ConnectionConfig<Vec<u8>>, ClientConnectionConfig) {
    let my_addr = SocketAddr{ ip: Ipv4Addr(0, 0, 0, 0), port: 0 };
    let target_addr = SocketAddr{ ip: Ipv4Addr(127, 0, 0, 1), port: port };
    let settings = ConnectionConfig::new(protocol_id, 10, deserializer, serializer);
    let client_settings = ClientConnectionConfig::new(1, Duration::seconds(1));
    (my_addr, target_addr, settings, client_settings)
}

fn get_message(socket: &mut UdpSocket) -> (Vec<u8>, SocketAddr) {
    let mut buf = [0, ..255];
    match socket.recv_from(buf) {
        Ok((amt, src)) => (buf.slice_to(amt).to_owned(), src),
        Err(e) => fail!("Socket didn't get a message")
    }
}

macro_rules! with_bound_socket(
    ($socket:ident, ($variable:ident)$code:block) => (
        spawn(proc() {
            match UdpSocket::bind($socket) {
                Ok(mut $variable) => $code,
                Err(e) => fail!(e)
            }
        });
    )
)

/**
 * Test when there isn't a backend to connect to
 * Connect should return an IOResult stating we can't get there
 */
#[test]
fn connection_ignored() {
    let port = 65000;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Reported connected when there is no server!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * Test a normal connection where the backend replies with an accept
 */
#[test]
fn standard_connection() {
    let port = 65001;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(client) => {
            //Success!
        },
        Err(e) => fail!(e)
    };
}

/**
 * If the server gives us back a different protocol id, we shouldn't accept it
 */
#[test]
fn connection_different_protocol_id() {
    let port = 65002;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(122).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server with a different protocol ID!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * If the server specifically rejects us, we should give up
 */
#[test]
fn connection_rejected() {
    let port = 65003;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::reject(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server that rejected us!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * We should be able to specify how many retries we want
 */
#[test]
fn different_retry_count() {
    let port = 65004;
    let (my_addr, target_addr, settings, mut client_settings) = generate_settings(port, 121);
    client_settings.max_connect_retries = 3;

    let (tx, rx) = channel();
    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let mut attempts = 0u8;
        while attempts < 3 {
            get_message(&mut socket);
            attempts += 1;
        }

        tx.send(attempts);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => (),
        Err(_) => ()
    };

    assert!(rx.recv() == 3);
}

//TODO: Find a sensible way of testing timeout lengths

/**
 * We should instantly return when polling and there's no data available
 */
#[test]
fn empty_polling() {
    let port = 65005;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            assert!(match client.poll() { Err(PollEmpty) => true, _ => false});
        },
        Err(e) => fail!(e)
    };
}

/**
 * We should return an item if there's one there
 */
#[test]
fn single_item_polling() {
    let port = 65006;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //May have to wait a bit
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            match client.poll() {
                Ok(packet) => {
                    assert!(packet == vec![1]);
                },
                Err(e) => fail!("Couldn't match a polled message! - {}", e)
            };
        },
        Err(e) => fail!(e)
    };
}

#[test]
fn multiple_item_polling() {
    let port = 65007;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![2]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![3]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    let mut packets: Vec<Vec<u8>> = vec![];

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Ok(packet) => packets.push(packet),
                    Err(PollEmpty) => break,
                    Err(e) => fail!("Unexpected failure - {}", e)
                };
            }
        },
        Err(e) => fail!(e)
    };

    assert!(packets.len() == 3);
    assert!(packets[0] == vec![1]);
    assert!(packets[1] == vec![2]);
    assert!(packets[2] == vec![3]);
}

#[test]
fn ignore_bad_queue_items_polling() {
    unimplemented!();
}

#[test]
fn disconnection() {
    unimplemented!();
}

#[test]
fn timeout() {
    unimplemented!();
}

#[test]
fn send_correct_handshake() {
    unimplemented!();
}

#[test]
fn send_data() {
    unimplemented!();
}
<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_web;
extern crate tokio_core;
extern crate reqwest;

use std::{net, thread};
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio_core::net::TcpListener;

use actix::*;
use actix_web::*;

fn create_server<T, A>() -> HttpServer<T, A, Application<()>> {
    HttpServer::new(
        vec![Application::default("/")
             .resource("/", |r|
                       r.handler(Method::GET, |_, _, _| {
                           httpcodes::HTTPOk
                       }))
             .finish()])
}

#[test]
fn test_serve() {
    thread::spawn(|| {
        let sys = System::new("test");
        let srv = create_server();
        srv.serve::<_, ()>("127.0.0.1:58902").unwrap();
        sys.run();
    });
    assert!(reqwest::get("http://localhost:58906/").unwrap().status().is_success());
}

#[test]
fn test_serve_incoming() {
    thread::spawn(|| {
        let sys = System::new("test");

        let srv = create_server();
        let addr = net::SocketAddr::from_str("127.0.0.1:58906").unwrap();
        let tcp = TcpListener::bind(&addr, Arbiter::handle()).unwrap();
        srv.serve_incoming::<_, ()>(tcp.incoming()).unwrap();
        sys.run();

    });

    assert!(reqwest::get("http://localhost:58906/").unwrap().status().is_success());
}

struct MiddlewareTest {
    start: Arc<AtomicUsize>,
    response: Arc<AtomicUsize>,
    finish: Arc<AtomicUsize>,
}

impl Middleware for MiddlewareTest {
    fn start(&self, _: &mut HttpRequest) -> Result<(), HttpResponse> {
        self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        Ok(())
    }

    fn response(&self, _: &mut HttpRequest, resp: HttpResponse) -> HttpResponse {
        self.response.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        resp
    }

    fn finish(&self, _: &mut HttpRequest, _: &HttpResponse) {
        self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
    }
}

#[test]
fn test_middlewares() {
    let num1 = Arc::new(AtomicUsize::new(0));
    let num2 = Arc::new(AtomicUsize::new(0));
    let num3 = Arc::new(AtomicUsize::new(0));

    let act_num1 = Arc::clone(&num1);
    let act_num2 = Arc::clone(&num2);
    let act_num3 = Arc::clone(&num3);

    thread::spawn(move || {
        let sys = System::new("test");

        HttpServer::new(
            vec![Application::default("/")
                 .middleware(MiddlewareTest{start: act_num1,
                                            response: act_num2,
                                            finish: act_num3})
                 .resource("/", |r|
                           r.handler(Method::GET, |_, _, _| {
                               httpcodes::HTTPOk
                           }))
                 .finish()])
            .serve::<_, ()>("127.0.0.1:58903").unwrap();
        sys.run();
    });

    assert!(reqwest::get("http://localhost:58903/").unwrap().status().is_success());

    assert_eq!(num1.load(Ordering::Relaxed), 1);
    assert_eq!(num2.load(Ordering::Relaxed), 1);
    assert_eq!(num3.load(Ordering::Relaxed), 1);
}
<commit_msg>fix test<commit_after>extern crate actix;
extern crate actix_web;
extern crate tokio_core;
extern crate reqwest;

use std::{net, thread};
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio_core::net::TcpListener;

use actix::*;
use actix_web::*;

fn create_server<T, A>() -> HttpServer<T, A, Application<()>> {
    HttpServer::new(
        vec![Application::default("/")
             .resource("/", |r|
                       r.handler(Method::GET, |_, _, _| {
                           httpcodes::HTTPOk
                       }))
             .finish()])
}

#[test]
fn test_serve() {
    thread::spawn(|| {
        let sys = System::new("test");
        let srv = create_server();
        srv.serve::<_, ()>("127.0.0.1:58902").unwrap();
        sys.run();
    });
    assert!(reqwest::get("http://localhost:58902/").unwrap().status().is_success());
}

#[test]
fn test_serve_incoming() {
    thread::spawn(|| {
        let sys = System::new("test");

        let srv = create_server();
        let addr = net::SocketAddr::from_str("127.0.0.1:58906").unwrap();
        let tcp = TcpListener::bind(&addr, Arbiter::handle()).unwrap();
        srv.serve_incoming::<_, ()>(tcp.incoming()).unwrap();
        sys.run();

    });

    assert!(reqwest::get("http://localhost:58906/").unwrap().status().is_success());
}

struct MiddlewareTest {
    start: Arc<AtomicUsize>,
    response: Arc<AtomicUsize>,
    finish: Arc<AtomicUsize>,
}

impl Middleware for MiddlewareTest {
    fn start(&self, _: &mut HttpRequest) -> Result<(), HttpResponse> {
        self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        Ok(())
    }

    fn response(&self, _: &mut HttpRequest, resp: HttpResponse) -> HttpResponse {
        self.response.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
        resp
    }

    fn finish(&self, _: &mut HttpRequest, _: &HttpResponse) {
        self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
    }
}

#[test]
fn test_middlewares() {
    let num1 = Arc::new(AtomicUsize::new(0));
    let num2 = Arc::new(AtomicUsize::new(0));
    let num3 = Arc::new(AtomicUsize::new(0));

    let act_num1 = Arc::clone(&num1);
    let act_num2 = Arc::clone(&num2);
    let act_num3 = Arc::clone(&num3);

    thread::spawn(move || {
        let sys = System::new("test");

        HttpServer::new(
            vec![Application::default("/")
                 .middleware(MiddlewareTest{start: act_num1,
                                            response: act_num2,
                                            finish: act_num3})
                 .resource("/", |r|
                           r.handler(Method::GET, |_, _, _| {
                               httpcodes::HTTPOk
                           }))
                 .finish()])
            .serve::<_, ()>("127.0.0.1:58903").unwrap();
        sys.run();
    });

    assert!(reqwest::get("http://localhost:58903/").unwrap().status().is_success());

    assert_eq!(num1.load(Ordering::Relaxed), 1);
    assert_eq!(num2.load(Ordering::Relaxed), 1);
    assert_eq!(num3.load(Ordering::Relaxed), 1);
}
<|endoftext|>


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

use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use descriptor::PipelineLayout;
use descriptor::pipeline_layout::PipelineLayoutDesc;
use descriptor::pipeline_layout::PipelineLayoutSuperset;
use pipeline::shader::ComputeShaderEntryPoint;
use pipeline::shader::SpecializationConstants;

use device::Device;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// A pipeline object that describes to the Vulkan implementation how it should perform compute
/// operations.
///
/// The template parameter contains the descriptor set to use with this pipeline.
pub struct ComputePipeline<Pl> {
    pipeline: vk::Pipeline,
    device: Arc<Device>,
    pipeline_layout: Arc<Pl>,
}

impl<Pl> ComputePipeline<Pl> {
    /// Builds a new `ComputePipeline`.
    pub fn new<Css, Csl>(device: &Arc<Device>, pipeline_layout: &Arc<Pl>,
                         shader: &ComputeShaderEntryPoint<Css, Csl>, specialization: &Css)
                         -> Result<Arc<ComputePipeline<Pl>>, ComputePipelineCreationError>
        where Pl: PipelineLayout + PipelineLayoutSuperset<Csl>, Csl: PipelineLayoutDesc,
              Css: SpecializationConstants
    {
        let vk = device.pointers();

        // TODO: more details in the error
        if !PipelineLayoutSuperset::is_superset_of(&**pipeline_layout, shader.layout()) {
            return Err(ComputePipelineCreationError::IncompatiblePipelineLayout);
        }

        let pipeline = unsafe {
            let spec_descriptors = <Css as SpecializationConstants>::descriptors();
            let specialization = vk::SpecializationInfo {
                mapEntryCount: spec_descriptors.len() as u32,
                pMapEntries: spec_descriptors.as_ptr() as *const _,
                dataSize: mem::size_of_val(specialization),
                pData: specialization as *const Css as *const _,
            };

            let stage = vk::PipelineShaderStageCreateInfo {
                sType: vk::STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,
                stage: vk::SHADER_STAGE_COMPUTE_BIT,
                module: shader.module().internal_object(),
                pName: shader.name().as_ptr(),
                pSpecializationInfo: if specialization.dataSize == 0 {
                    ptr::null()
                } else {
                    &specialization
                },
            };

            let infos = vk::ComputePipelineCreateInfo {
                sType: vk::STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,
                stage: stage,
                layout: PipelineLayout::inner_pipeline_layout(&**pipeline_layout).internal_object(),
                basePipelineHandle: 0,
                basePipelineIndex: 0,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateComputePipelines(device.internal_object(), 0,
                                                        1, &infos, ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(ComputePipeline {
            device: device.clone(),
            pipeline: pipeline,
            pipeline_layout: pipeline_layout.clone(),
        }))
    }

    /// Returns the `Device` this compute pipeline was created with.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    /// Returns the pipeline layout used in this compute pipeline.
    #[inline]
    pub fn layout(&self) -> &Arc<Pl> {
        &self.pipeline_layout
    }
}

unsafe impl<Pl> VulkanObject for ComputePipeline<Pl> {
    type Object = vk::Pipeline;

    #[inline]
    fn internal_object(&self) -> vk::Pipeline {
        self.pipeline
    }
}

impl<Pl> Drop for ComputePipeline<Pl> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyPipeline(self.device.internal_object(), self.pipeline, ptr::null());
        }
    }
}

/// Error that can happen when creating a compute pipeline.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ComputePipelineCreationError {
    /// Not enough memory.
    OomError(OomError),
    /// The pipeline layout is not compatible with what the shader expects.
    IncompatiblePipelineLayout,
}

impl error::Error for ComputePipelineCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            ComputePipelineCreationError::OomError(_) => "not enough memory available",
            ComputePipelineCreationError::IncompatiblePipelineLayout => "the pipeline layout is \
                                                                         not compatible with what \
                                                                         the shader expects",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ComputePipelineCreationError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for ComputePipelineCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for ComputePipelineCreationError {
    #[inline]
    fn from(err: OomError) -> ComputePipelineCreationError {
        ComputePipelineCreationError::OomError(err)
    }
}

impl From<Error> for ComputePipelineCreationError {
    #[inline]
    fn from(err: Error) -> ComputePipelineCreationError {
        match err {
            err @ Error::OutOfHostMemory => {
                ComputePipelineCreationError::OomError(OomError::from(err))
            },
            err @ Error::OutOfDeviceMemory => {
                ComputePipelineCreationError::OomError(OomError::from(err))
            },
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

#[cfg(test)]
mod tests {
    // TODO: test for basic creation
    // TODO: test for pipeline layout error
}
<commit_msg>Typo: struct created using incorrect sType causing validation error<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use descriptor::PipelineLayout;
use descriptor::pipeline_layout::PipelineLayoutDesc;
use descriptor::pipeline_layout::PipelineLayoutSuperset;
use pipeline::shader::ComputeShaderEntryPoint;
use pipeline::shader::SpecializationConstants;

use device::Device;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// A pipeline object that describes to the Vulkan implementation how it should perform compute
/// operations.
///
/// The template parameter contains the descriptor set to use with this pipeline.
pub struct ComputePipeline<Pl> {
    pipeline: vk::Pipeline,
    device: Arc<Device>,
    pipeline_layout: Arc<Pl>,
}

impl<Pl> ComputePipeline<Pl> {
    /// Builds a new `ComputePipeline`.
    pub fn new<Css, Csl>(device: &Arc<Device>, pipeline_layout: &Arc<Pl>,
                         shader: &ComputeShaderEntryPoint<Css, Csl>, specialization: &Css)
                         -> Result<Arc<ComputePipeline<Pl>>, ComputePipelineCreationError>
        where Pl: PipelineLayout + PipelineLayoutSuperset<Csl>, Csl: PipelineLayoutDesc,
              Css: SpecializationConstants
    {
        let vk = device.pointers();

        // TODO: more details in the error
        if !PipelineLayoutSuperset::is_superset_of(&**pipeline_layout, shader.layout()) {
            return Err(ComputePipelineCreationError::IncompatiblePipelineLayout);
        }

        let pipeline = unsafe {
            let spec_descriptors = <Css as SpecializationConstants>::descriptors();
            let specialization = vk::SpecializationInfo {
                mapEntryCount: spec_descriptors.len() as u32,
                pMapEntries: spec_descriptors.as_ptr() as *const _,
                dataSize: mem::size_of_val(specialization),
                pData: specialization as *const Css as *const _,
            };

            let stage = vk::PipelineShaderStageCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,
                stage: vk::SHADER_STAGE_COMPUTE_BIT,
                module: shader.module().internal_object(),
                pName: shader.name().as_ptr(),
                pSpecializationInfo: if specialization.dataSize == 0 {
                    ptr::null()
                } else {
                    &specialization
                },
            };

            let infos = vk::ComputePipelineCreateInfo {
                sType: vk::STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,
                stage: stage,
                layout: PipelineLayout::inner_pipeline_layout(&**pipeline_layout).internal_object(),
                basePipelineHandle: 0,
                basePipelineIndex: 0,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateComputePipelines(device.internal_object(), 0,
                                                        1, &infos, ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(ComputePipeline {
            device: device.clone(),
            pipeline: pipeline,
            pipeline_layout: pipeline_layout.clone(),
        }))
    }

    /// Returns the `Device` this compute pipeline was created with.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    /// Returns the pipeline layout used in this compute pipeline.
    #[inline]
    pub fn layout(&self) -> &Arc<Pl> {
        &self.pipeline_layout
    }
}

unsafe impl<Pl> VulkanObject for ComputePipeline<Pl> {
    type Object = vk::Pipeline;

    #[inline]
    fn internal_object(&self) -> vk::Pipeline {
        self.pipeline
    }
}

impl<Pl> Drop for ComputePipeline<Pl> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyPipeline(self.device.internal_object(), self.pipeline, ptr::null());
        }
    }
}

/// Error that can happen when creating a compute pipeline.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ComputePipelineCreationError {
    /// Not enough memory.
    OomError(OomError),
    /// The pipeline layout is not compatible with what the shader expects.
    IncompatiblePipelineLayout,
}

impl error::Error for ComputePipelineCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            ComputePipelineCreationError::OomError(_) => "not enough memory available",
            ComputePipelineCreationError::IncompatiblePipelineLayout => "the pipeline layout is \
                                                                         not compatible with what \
                                                                         the shader expects",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ComputePipelineCreationError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for ComputePipelineCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for ComputePipelineCreationError {
    #[inline]
    fn from(err: OomError) -> ComputePipelineCreationError {
        ComputePipelineCreationError::OomError(err)
    }
}

impl From<Error> for ComputePipelineCreationError {
    #[inline]
    fn from(err: Error) -> ComputePipelineCreationError {
        match err {
            err @ Error::OutOfHostMemory => {
                ComputePipelineCreationError::OomError(OomError::from(err))
            },
            err @ Error::OutOfDeviceMemory => {
                ComputePipelineCreationError::OomError(OomError::from(err))
            },
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

#[cfg(test)]
mod tests {
    // TODO: test for basic creation
    // TODO: test for pipeline layout error
}
<|endoftext|>