<commit_before>
use std::io;
use std::iter;
use std::slice::Iter;

use parser::ast::*;
use processing::structs::*;
use scope::scope::*;
use scope::context::*;
use scope::bindings::*;
use output::stream_writers::output_writer::*;
use output::stream_writers::output_stream_writer::*;

// pub type PropIterator = IntoIter<Item = Prop>;
// pub type EventHandlerIterator = IntoIter<Item = EventHandler>;
// pub type BindingIterator = IntoIterator<Item = ElementValueBinding>;

#[derive(Debug, Clone, Default)]
pub struct ElementOpsStreamWriterJs {}

// impl<X: ExprWriter> ElementOpsStreamWriter<X> for ElementOpsStreamWriterJs {
impl<X: ExprWriter> ElementOpsStreamWriter for X {
    fn write_op_element_open<PropIter, EventIter, BindingIter>(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, element_tag: &str, element_key: &str, is_void: bool, props: PropIter, events: EventIter, binding: BindingIter) -> Result
        where PropIter : IntoIterator<Item = Prop>, EventIter: IntoIterator<Item = EventHandler>, BindingIter: IntoIterator<Item = ElementValueBinding>
    {
        if !is_void {
            write!(w, "IncrementalDOM.elementOpen(\"{}\", ", element_tag)?;
        } else {
            write!(w, "IncrementalDOM.elementVoid(\"{}\", ", element_tag)?;
        };

        // let path_expr = ctx.scope_ref().unwrap().join_path_as_expr(Some("."));
        let path_expr = ctx.join_path_as_expr(Some("."));
        self.write_expr(w, ctx, bindings, &path_expr)?;

        // write_js_expr_value(w, scope, path_expr)?;
        // write_js_func_params(scope, w)?;
        writeln!(w, ");")?;

        Ok(())
    }

    fn write_op_element_close(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, element_tag: &str, element_key: &str) -> Result {
        writeln!(w, "IncrementalDOM.elementClose(\"{}\");", element_tag)?;
        Ok(())
    }

    fn write_op_element_start_block<PropIter: IntoIterator<Item = Prop>>(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, block_id: &str, props: PropIter) -> Result {
        Ok(())
    }

    fn write_op_element_end_block(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, block_id: &str) -> Result {
        Ok(())
    }

    fn write_op_element_map_collection_to_block(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, coll_expr: &ExprValue, block_id: &str) -> Result {
        write!(w, "(")?;
        let binding = BindingType::LoopIndexBinding;
        writeln!(w, ").forEach(__{});", block_id)?;
        Ok(())
    }

    fn write_op_element_instance_component<PropIter, EventIter, BindingIter>(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, element_tag: &str, element_key: &str, is_void: bool, props: PropIter, events: EventIter, binding: BindingIter) -> Result
        where PropIter : IntoIterator<Item = Prop>, EventIter: IntoIterator<Item = EventHandler>, BindingIter: IntoIterator<Item = ElementValueBinding>
    {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str;
    use std::iter::empty;
    use scope::context::*;
    use scope::bindings::*;
    use output::stream_writers::output_writer_js::*;

    #[test]
    pub fn test_output_stream_writers_js_ops1() {
        // let scope = Scope::default();
        let mut ctx = Context::default();
        ctx.append_path_str("prefix");
        let bindings = BindingContext::default();

        // let mut value_writer = ValueWriterJs::default();
        // let mut expr_writer = ExpressionWriterJs::default();
        // let mut stream_writer = ElementOpsStreamWriterJs::default();

        let mut writer: DefaultOutputWriter<ValueWriterJs, ExpressionWriterJs> = DefaultOutputWriter::default();

        let mut s: Vec<u8> = Default::default();
        let key = "key".to_owned();
        ctx.append_path_str(&key);
        assert!(
            writer.write_op_element_open(&mut s, &mut ctx, &bindings, "span", &key, false, empty(), empty(), empty()).is_ok() &&
            writer.write_op_element_close(&mut s,&mut ctx, &bindings, "span", &key).is_ok()
        );
        assert_eq!(str::from_utf8(&s), Ok("IncrementalDOM.elementOpen(\"span\", [\"prefix\", \"key\"].join(\".\"));\nIncrementalDOM.elementClose(\"span\");\n".into()));
    }
}<commit_msg>Update ElementOpsStreamWriter impl for javascript to require ExpressionWriterJs (could be converted to a trait).<commit_after>
use std::io;
use std::iter;
use std::slice::Iter;

use parser::ast::*;
use processing::structs::*;
use scope::scope::*;
use scope::context::*;
use scope::bindings::*;
use output::stream_writers::output_writer::*;
use output::stream_writers::output_stream_writer::*;
use output::stream_writers::output_writer_js::*;

// pub type PropIterator = IntoIter<Item = Prop>;
// pub type EventHandlerIterator = IntoIter<Item = EventHandler>;
// pub type BindingIterator = IntoIterator<Item = ElementValueBinding>;

#[derive(Debug, Clone, Default)]
pub struct ElementOpsStreamWriterJs {}

// impl<X: ExprWriter> ElementOpsStreamWriter<X> for ElementOpsStreamWriterJs {
impl<X: ExprWriter<E = ExpressionWriterJs>> ElementOpsStreamWriter for X {
    fn write_op_element_open<PropIter, EventIter, BindingIter>(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, element_tag: &str, element_key: &str, is_void: bool, props: PropIter, events: EventIter, binding: BindingIter) -> Result
        where PropIter : IntoIterator<Item = Prop>, EventIter: IntoIterator<Item = EventHandler>, BindingIter: IntoIterator<Item = ElementValueBinding>
    {
        if !is_void {
            write!(w, "IncrementalDOM.elementOpen(\"{}\", ", element_tag)?;
        } else {
            write!(w, "IncrementalDOM.elementVoid(\"{}\", ", element_tag)?;
        };

        // let path_expr = ctx.scope_ref().unwrap().join_path_as_expr(Some("."));
        let path_expr = ctx.join_path_as_expr(Some("."));
        self.write_expr(w, ctx, bindings, &path_expr)?;

        // write_js_expr_value(w, scope, path_expr)?;
        // write_js_func_params(scope, w)?;
        writeln!(w, ");")?;

        Ok(())
    }

    fn write_op_element_close(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, element_tag: &str, element_key: &str) -> Result {
        writeln!(w, "IncrementalDOM.elementClose(\"{}\");", element_tag)?;
        Ok(())
    }

    fn write_op_element_start_block<PropIter: IntoIterator<Item = Prop>>(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, block_id: &str, props: PropIter) -> Result {
        Ok(())
    }

    fn write_op_element_end_block(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, block_id: &str) -> Result {
        Ok(())
    }

    fn write_op_element_map_collection_to_block(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, coll_expr: &ExprValue, block_id: &str) -> Result {
        write!(w, "(")?;
        let binding = BindingType::LoopIndexBinding;
        writeln!(w, ").forEach(__{});", block_id)?;
        Ok(())
    }

    fn write_op_element_instance_component<PropIter, EventIter, BindingIter>(&mut self, w: &mut io::Write, ctx: &mut Context, bindings: &BindingContext, element_tag: &str, element_key: &str, is_void: bool, props: PropIter, events: EventIter, binding: BindingIter) -> Result
        where PropIter : IntoIterator<Item = Prop>, EventIter: IntoIterator<Item = EventHandler>, BindingIter: IntoIterator<Item = ElementValueBinding>
    {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str;
    use std::iter::empty;
    use scope::context::*;
    use scope::bindings::*;
    use output::stream_writers::output_writer_js::*;

    #[test]
    pub fn test_output_stream_writers_js_ops1() {
        // let scope = Scope::default();
        let mut ctx = Context::default();
        ctx.append_path_str("prefix");
        let bindings = BindingContext::default();

        // let mut value_writer = ValueWriterJs::default();
        // let mut expr_writer = ExpressionWriterJs::default();
        // let mut stream_writer = ElementOpsStreamWriterJs::default();

        let mut writer: DefaultOutputWriter<ValueWriterJs, ExpressionWriterJs> = DefaultOutputWriter::default();

        let mut s: Vec<u8> = Default::default();
        let key = "key".to_owned();
        ctx.append_path_str(&key);
        assert!(
            writer.write_op_element_open(&mut s, &mut ctx, &bindings, "span", &key, false, empty(), empty(), empty()).is_ok() &&
            writer.write_op_element_close(&mut s,&mut ctx, &bindings, "span", &key).is_ok()
        );
        assert_eq!(str::from_utf8(&s), Ok("IncrementalDOM.elementOpen(\"span\", [\"prefix\", \"key\"].join(\".\"));\nIncrementalDOM.elementClose(\"span\");\n".into()));
    }
}<|endoftext|>


<commit_before>extern crate libc;
use std::str;
use std::ffi;
use std::ptr;
use self::libc::{size_t, c_char, time_t, uint32_t};

#[repr(C)]
pub struct memcached_st;

#[repr(C)]
#[derive(Debug)]
pub enum memcached_return_t {
    MEMCACHED_SUCCESS,
    MEMCACHED_FAILURE,
    MEMCACHED_HOST_LOOKUP_FAILURE, // getaddrinfo() and getnameinfo() only
    MEMCACHED_CONNECTION_FAILURE,
    MEMCACHED_CONNECTION_BIND_FAILURE,  // DEPRECATED, see MEMCACHED_HOST_LOOKUP_FAILURE
    MEMCACHED_WRITE_FAILURE,
    MEMCACHED_READ_FAILURE,
    MEMCACHED_UNKNOWN_READ_FAILURE,
    MEMCACHED_PROTOCOL_ERROR,
    MEMCACHED_CLIENT_ERROR,
    MEMCACHED_SERVER_ERROR, // Server returns "SERVER_ERROR"
    MEMCACHED_ERROR, // Server returns "ERROR"
    MEMCACHED_DATA_EXISTS,
    MEMCACHED_DATA_DOES_NOT_EXIST,
    MEMCACHED_NOTSTORED,
    MEMCACHED_STORED,
    MEMCACHED_NOTFOUND,
    MEMCACHED_MEMORY_ALLOCATION_FAILURE,
    MEMCACHED_PARTIAL_READ,
    MEMCACHED_SOME_ERRORS,
    MEMCACHED_NO_SERVERS,
    MEMCACHED_END,
    MEMCACHED_DELETED,
    MEMCACHED_VALUE,
    MEMCACHED_STAT,
    MEMCACHED_ITEM,
    MEMCACHED_ERRNO,
    MEMCACHED_FAIL_UNIX_SOCKET, // DEPRECATED
    MEMCACHED_NOT_SUPPORTED,
    MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
    MEMCACHED_FETCH_NOTFINISHED,
    MEMCACHED_TIMEOUT,
    MEMCACHED_BUFFERED,
    MEMCACHED_BAD_KEY_PROVIDED,
    MEMCACHED_INVALID_HOST_PROTOCOL,
    MEMCACHED_SERVER_MARKED_DEAD,
    MEMCACHED_UNKNOWN_STAT_KEY,
    MEMCACHED_E2BIG,
    MEMCACHED_INVALID_ARGUMENTS,
    MEMCACHED_KEY_TOO_BIG,
    MEMCACHED_AUTH_PROBLEM,
    MEMCACHED_AUTH_FAILURE,
    MEMCACHED_AUTH_CONTINUE,
    MEMCACHED_PARSE_ERROR,
    MEMCACHED_PARSE_USER_ERROR,
    MEMCACHED_DEPRECATED,
    MEMCACHED_IN_PROGRESS,
    MEMCACHED_SERVER_TEMPORARILY_DISABLED,
    MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE,
    MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
    // MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE= MEMCACHED_ERROR
}

#[must_use]
pub type MemcacheErrorCode = memcached_return_t;

#[link(name = "memcached")]
extern {
    pub fn memcached(string: *const c_char, string_length: size_t) -> *const memcached_st;
    pub fn memcached_last_error_message(client: *const memcached_st) -> *const c_char;
    pub fn memcached_strerror(client: *const memcached_st, rc: memcached_return_t) -> *const c_char;
    pub fn memcached_set(client: *const memcached_st, key: *const c_char, key_length: size_t, value: *const c_char, value_length: size_t, expiration: time_t, flag: uint32_t) -> memcached_return_t;
    pub fn memcached_get(client: *const memcached_st, key: *const c_char, key_length: size_t, value_length: *mut size_t, flags: *mut uint32_t, error: *mut memcached_return_t) -> *const c_char;
    pub fn memcached_flush(client: *const memcached_st, expiration: time_t) -> memcached_return_t;
}

#[test]
fn test_memcaced() {
    unsafe {
        let s = "--SERVER=localhost";
        let string = ffi::CString::new(s).unwrap();
        let client = memcached(string.as_ptr(), 18);
        assert!(!client.is_null());
    }
}

#[test]
fn test_memcached_last_error_message() {
    unsafe {
        let string = ffi::CString::new("foo").unwrap();
        let client = memcached(string.as_ptr(), 3);
        let error = memcached_last_error_message(client);
        let slice = ffi::CStr::from_ptr(error);
        println!("string returned: {}", str::from_utf8(slice.to_bytes()).unwrap());
        assert!(!error.is_null());
    }
}

#[test]
fn test_memcached_operations() {
    unsafe{
        // client
        let s = "--SERVER=localhost";
        let string = ffi::CString::new(s).unwrap();
        let client = memcached(string.as_ptr(), 18);
        assert!(!client.is_null());

        // flush
        let r = memcached_flush(client, 0);
        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {}
            _ => panic!()
        }

        // set foo bar
        let key = ffi::CString::new("foo").unwrap();
        let key_length = 3;
        let value = ffi::CString::new("bar").unwrap();
        let value_length = 3;
        let r = memcached_set(client, key.as_ptr(), key_length, value.as_ptr(), value_length, 0, 0);

        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {}
            _ => panic!()
        }

        // get foo == bar
        let mut value_length: size_t = 0;
        let value_length_ptr: *mut size_t = &mut value_length;

        let mut flags: uint32_t = 0;
        let flags_ptr: *mut uint32_t = &mut flags;

        let mut error: memcached_return_t = memcached_return_t::MEMCACHED_FAILURE;
        let error_ptr: *mut memcached_return_t = &mut error;

        let r = memcached_get(client, key.as_ptr(), key_length, value_length_ptr, flags_ptr, error_ptr);

        println!("value: {:?}, error: {:?}, value_length: {:?}", r, error_ptr, value_length_ptr);
        assert!(value_length == 3);
        match error {
            memcached_return_t::MEMCACHED_SUCCESS => {}
            _ => panic!()
        }
        let slice = ffi::CStr::from_ptr(r);
        assert!(str::from_utf8(slice.to_bytes()).unwrap() == "bar");
    }
}
<commit_msg>set test memcached port to 2333<commit_after>extern crate libc;
use std::str;
use std::ffi;
use std::ptr;
use self::libc::{size_t, c_char, time_t, uint32_t};

#[repr(C)]
pub struct memcached_st;

#[repr(C)]
#[derive(Debug)]
pub enum memcached_return_t {
    MEMCACHED_SUCCESS,
    MEMCACHED_FAILURE,
    MEMCACHED_HOST_LOOKUP_FAILURE, // getaddrinfo() and getnameinfo() only
    MEMCACHED_CONNECTION_FAILURE,
    MEMCACHED_CONNECTION_BIND_FAILURE,  // DEPRECATED, see MEMCACHED_HOST_LOOKUP_FAILURE
    MEMCACHED_WRITE_FAILURE,
    MEMCACHED_READ_FAILURE,
    MEMCACHED_UNKNOWN_READ_FAILURE,
    MEMCACHED_PROTOCOL_ERROR,
    MEMCACHED_CLIENT_ERROR,
    MEMCACHED_SERVER_ERROR, // Server returns "SERVER_ERROR"
    MEMCACHED_ERROR, // Server returns "ERROR"
    MEMCACHED_DATA_EXISTS,
    MEMCACHED_DATA_DOES_NOT_EXIST,
    MEMCACHED_NOTSTORED,
    MEMCACHED_STORED,
    MEMCACHED_NOTFOUND,
    MEMCACHED_MEMORY_ALLOCATION_FAILURE,
    MEMCACHED_PARTIAL_READ,
    MEMCACHED_SOME_ERRORS,
    MEMCACHED_NO_SERVERS,
    MEMCACHED_END,
    MEMCACHED_DELETED,
    MEMCACHED_VALUE,
    MEMCACHED_STAT,
    MEMCACHED_ITEM,
    MEMCACHED_ERRNO,
    MEMCACHED_FAIL_UNIX_SOCKET, // DEPRECATED
    MEMCACHED_NOT_SUPPORTED,
    MEMCACHED_NO_KEY_PROVIDED, /* Deprecated. Use MEMCACHED_BAD_KEY_PROVIDED! */
    MEMCACHED_FETCH_NOTFINISHED,
    MEMCACHED_TIMEOUT,
    MEMCACHED_BUFFERED,
    MEMCACHED_BAD_KEY_PROVIDED,
    MEMCACHED_INVALID_HOST_PROTOCOL,
    MEMCACHED_SERVER_MARKED_DEAD,
    MEMCACHED_UNKNOWN_STAT_KEY,
    MEMCACHED_E2BIG,
    MEMCACHED_INVALID_ARGUMENTS,
    MEMCACHED_KEY_TOO_BIG,
    MEMCACHED_AUTH_PROBLEM,
    MEMCACHED_AUTH_FAILURE,
    MEMCACHED_AUTH_CONTINUE,
    MEMCACHED_PARSE_ERROR,
    MEMCACHED_PARSE_USER_ERROR,
    MEMCACHED_DEPRECATED,
    MEMCACHED_IN_PROGRESS,
    MEMCACHED_SERVER_TEMPORARILY_DISABLED,
    MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE,
    MEMCACHED_MAXIMUM_RETURN, /* Always add new error code before */
    // MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE= MEMCACHED_ERROR
}

#[must_use]
pub type MemcacheErrorCode = memcached_return_t;

#[link(name = "memcached")]
extern {
    pub fn memcached(string: *const c_char, string_length: size_t) -> *const memcached_st;
    pub fn memcached_last_error_message(client: *const memcached_st) -> *const c_char;
    pub fn memcached_strerror(client: *const memcached_st, rc: memcached_return_t) -> *const c_char;
    pub fn memcached_set(client: *const memcached_st, key: *const c_char, key_length: size_t, value: *const c_char, value_length: size_t, expiration: time_t, flag: uint32_t) -> memcached_return_t;
    pub fn memcached_get(client: *const memcached_st, key: *const c_char, key_length: size_t, value_length: *mut size_t, flags: *mut uint32_t, error: *mut memcached_return_t) -> *const c_char;
    pub fn memcached_flush(client: *const memcached_st, expiration: time_t) -> memcached_return_t;
}

#[test]
fn test_memcaced() {
    unsafe {
        let s = "--SERVER=localhost:2333";
        let string = ffi::CString::new(s).unwrap();
        let client = memcached(string.as_ptr(), 23);
        assert!(!client.is_null());
    }
}

#[test]
fn test_memcached_last_error_message() {
    unsafe {
        let string = ffi::CString::new("foo").unwrap();
        let client = memcached(string.as_ptr(), 3);
        let error = memcached_last_error_message(client);
        let slice = ffi::CStr::from_ptr(error);
        // println!("string returned: {}", str::from_utf8(slice.to_bytes()).unwrap());
        assert!(!error.is_null());
    }
}

#[test]
fn test_memcached_operations() {
    unsafe{
        // client
        let s = "--SERVER=localhost:2333";
        let string = ffi::CString::new(s).unwrap();
        let client = memcached(string.as_ptr(), 23);
        assert!(!client.is_null());

        // flush
        let r = memcached_flush(client, 0);
        let error = memcached_last_error_message(client);
        let slice = ffi::CStr::from_ptr(error);
        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {}
            _ => panic!()
        }

        // set foo bar
        let key = ffi::CString::new("foo").unwrap();
        let key_length = 3;
        let value = ffi::CString::new("bar").unwrap();
        let value_length = 3;
        let r = memcached_set(client, key.as_ptr(), key_length, value.as_ptr(), value_length, 0, 0);

        match r {
            memcached_return_t::MEMCACHED_SUCCESS => {}
            _ => panic!()
        }

        // get foo == bar
        let mut value_length: size_t = 0;
        let value_length_ptr: *mut size_t = &mut value_length;

        let mut flags: uint32_t = 0;
        let flags_ptr: *mut uint32_t = &mut flags;

        let mut error: memcached_return_t = memcached_return_t::MEMCACHED_FAILURE;
        let error_ptr: *mut memcached_return_t = &mut error;

        let r = memcached_get(client, key.as_ptr(), key_length, value_length_ptr, flags_ptr, error_ptr);

        // println!("value: {:?}, error: {:?}, value_length: {:?}", r, error_ptr, value_length_ptr);
        assert!(value_length == 3);
        match error {
            memcached_return_t::MEMCACHED_SUCCESS => {}
            _ => panic!()
        }
        let slice = ffi::CStr::from_ptr(r);
        assert!(str::from_utf8(slice.to_bytes()).unwrap() == "bar");
    }
}
<|endoftext|>


<commit_before>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

// This module is heavily commented as it contains most of the unsafe code in
// Syn, and caution should be used when editing it. The public-facing interface
// is 100% safe but the implementation is fragile internally.

#[cfg(all(
    not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
    feature = "proc-macro"
))]
use crate::proc_macro as pm;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

use std::marker::PhantomData;
use std::ptr;

use crate::Lifetime;

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
enum Entry {
    // Mimicking types from proc-macro.
    Group(Group, TokenBuffer),
    Ident(Ident),
    Punct(Punct),
    Literal(Literal),
    // End entries contain a raw pointer to the entry from the containing
    // token tree, or null if this is the outermost level.
    End(*const Entry),
}

/// A buffer that can be efficiently traversed multiple times, unlike
/// `TokenStream` which requires a deep copy in order to traverse more than
/// once.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not derive clone on this - there are raw pointers inside which
    // will be messed up. Moving the `TokenBuffer` itself is safe as the actual
    // backing slices won't be moved.
    data: Box<[Entry]>,
}

impl TokenBuffer {
    // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
    // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
    fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
        // Build up the entries list, recording the locations of any Groups
        // in the list to be processed later.
        let mut entries = Vec::new();
        let mut seqs = Vec::new();
        for tt in stream {
            match tt {
                TokenTree::Ident(sym) => {
                    entries.push(Entry::Ident(sym));
                }
                TokenTree::Punct(op) => {
                    entries.push(Entry::Punct(op));
                }
                TokenTree::Literal(l) => {
                    entries.push(Entry::Literal(l));
                }
                TokenTree::Group(g) => {
                    // Record the index of the interesting entry, and store an
                    // `End(null)` there temporarially.
                    seqs.push((entries.len(), g));
                    entries.push(Entry::End(ptr::null()));
                }
            }
        }
        // Add an `End` entry to the end with a reference to the enclosing token
        // stream which was passed in.
        entries.push(Entry::End(up));

        // NOTE: This is done to ensure that we don't accidentally modify the
        // length of the backing buffer. The backing buffer must remain at a
        // constant address after this point, as we are going to store a raw
        // pointer into it.
        let mut entries = entries.into_boxed_slice();
        for (idx, group) in seqs {
            // We know that this index refers to one of the temporary
            // `End(null)` entries, and we know that the last entry is
            // `End(up)`, so the next index is also valid.
            let seq_up = &entries[idx + 1] as *const Entry;

            // The end entry stored at the end of this Entry::Group should
            // point to the Entry which follows the Group in the list.
            let inner = Self::inner_new(group.stream(), seq_up);
            entries[idx] = Entry::Group(group, inner);
        }

        TokenBuffer { data: entries }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    ///
    /// *This method is available if Syn is built with both the `"parsing"` and
    /// `"proc-macro"` features.*
    #[cfg(all(
        not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
        feature = "proc-macro"
    ))]
    pub fn new(stream: pm::TokenStream) -> TokenBuffer {
        Self::new2(stream.into())
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    pub fn new2(stream: TokenStream) -> TokenBuffer {
        Self::inner_new(stream, ptr::null())
    }

    /// Creates a cursor referencing the first token in the buffer and able to
    /// traverse until the end of the buffer.
    pub fn begin(&self) -> Cursor {
        unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
    }
}

/// A cheaply copyable cursor into a `TokenBuffer`.
///
/// This cursor holds a shared reference into the immutable data which is used
/// internally to represent a `TokenStream`, and can be efficiently manipulated
/// and copied around.
///
/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
/// object and get a cursor to its first token with `begin()`.
///
/// Two cursors are equal if they have the same location in the same input
/// stream, and have the same scope.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Cursor<'a> {
    // The current entry which the `Cursor` is pointing at.
    ptr: *const Entry,
    // This is the only `Entry::End(..)` object which this cursor is allowed to
    // point at. All other `End` objects are skipped over in `Cursor::create`.
    scope: *const Entry,
    // Cursor is covariant in 'a. This field ensures that our pointers are still
    // valid.
    marker: PhantomData<&'a Entry>,
}

impl<'a> Cursor<'a> {
    /// Creates a cursor referencing a static empty TokenStream.
    pub fn empty() -> Self {
        // It's safe in this situation for us to put an `Entry` object in global
        // storage, despite it not actually being safe to send across threads
        // (`Ident` is a reference into a thread-local table). This is because
        // this entry never includes a `Ident` object.
        //
        // This wrapper struct allows us to break the rules and put a `Sync`
        // object in global storage.
        struct UnsafeSyncEntry(Entry);
        unsafe impl Sync for UnsafeSyncEntry {}
        static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));

        Cursor {
            ptr: &EMPTY_ENTRY.0,
            scope: &EMPTY_ENTRY.0,
            marker: PhantomData,
        }
    }

    /// This create method intelligently exits non-explicitly-entered
    /// `None`-delimited scopes when the cursor reaches the end of them,
    /// allowing for them to be treated transparently.
    unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
        // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
        // past it, unless `ptr == scope`, which means that we're at the edge of
        // our cursor's scope. We should only have `ptr != scope` at the exit
        // from None-delimited groups entered with `ignore_none`.
        while let Entry::End(exit) = *ptr {
            if ptr == scope {
                break;
            }
            ptr = exit;
        }

        Cursor {
            ptr,
            scope,
            marker: PhantomData,
        }
    }

    /// Get the current entry.
    fn entry(self) -> &'a Entry {
        unsafe { &*self.ptr }
    }

    /// Bump the cursor to point at the next token after the current one. This
    /// is undefined behavior if the cursor is currently looking at an
    /// `Entry::End`.
    unsafe fn bump(self) -> Cursor<'a> {
        Cursor::create(self.ptr.offset(1), self.scope)
    }

    /// If the cursor is looking at a `None`-delimited group, move it to look at
    /// the first token inside instead. If the group is empty, this will move
    /// the cursor past the `None`-delimited group.
    ///
    /// WARNING: This mutates its argument.
    fn ignore_none(&mut self) {
        if let Entry::Group(group, buf) = self.entry() {
            if group.delimiter() == Delimiter::None {
                // NOTE: We call `Cursor::create` here to make sure that
                // situations where we should immediately exit the span after
                // entering it are handled correctly.
                unsafe {
                    *self = Cursor::create(&buf.data[0], self.scope);
                }
            }
        }
    }

    /// Checks whether the cursor is currently pointing at the end of its valid
    /// scope.
    pub fn eof(self) -> bool {
        // We're at eof if we're at the end of our scope.
        self.ptr == self.scope
    }

    /// If the cursor is pointing at a `Group` with the given delimiter, returns
    /// a cursor into that group and one pointing to the next `TokenTree`.
    pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
        // If we're not trying to enter a none-delimited group, we want to
        // ignore them. We have to make sure to _not_ ignore them when we want
        // to enter them, of course. For obvious reasons.
        if delim != Delimiter::None {
            self.ignore_none();
        }

        if let Entry::Group(group, buf) = self.entry() {
            if group.delimiter() == delim {
                return Some((buf.begin(), group.span(), unsafe { self.bump() }));
            }
        }

        None
    }

    /// If the cursor is pointing at a `Ident`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at an `Punct`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(op) if op.as_char() != '\'' => Some((op.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Literal`, return it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Literal(lit) => Some((lit.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Lifetime`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump() };
                match next.ident() {
                    Some((ident, rest)) => {
                        let lifetime = Lifetime {
                            apostrophe: op.span(),
                            ident,
                        };
                        Some((lifetime, rest))
                    }
                    None => None,
                }
            }
            _ => None,
        }
    }

    /// Copies all remaining tokens visible from this cursor into a
    /// `TokenStream`.
    pub fn token_stream(self) -> TokenStream {
        let mut tts = Vec::new();
        let mut cursor = self;
        while let Some((tt, rest)) = cursor.token_tree() {
            tts.push(tt);
            cursor = rest;
        }
        tts.into_iter().collect()
    }

    /// If the cursor is pointing at a `TokenTree`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    ///
    /// Returns `None` if the cursor has reached the end of its stream.
    ///
    /// This method does not treat `None`-delimited groups as transparent, and
    /// will return a `Group(None, ..)` if the cursor is looking at one.
    pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
        let tree = match self.entry() {
            Entry::Group(group, _) => group.clone().into(),
            Entry::Literal(lit) => lit.clone().into(),
            Entry::Ident(ident) => ident.clone().into(),
            Entry::Punct(op) => op.clone().into(),
            Entry::End(..) => {
                return None;
            }
        };

        Some((tree, unsafe { self.bump() }))
    }

    /// Returns the `Span` of the current token, or `Span::call_site()` if this
    /// cursor points to eof.
    pub fn span(self) -> Span {
        match self.entry() {
            Entry::Group(group, _) => group.span(),
            Entry::Literal(l) => l.span(),
            Entry::Ident(t) => t.span(),
            Entry::Punct(o) => o.span(),
            Entry::End(..) => Span::call_site(),
        }
    }

    /// Skip over the next token without cloning it. Returns `None` if this
    /// cursor points to eof.
    ///
    /// This method treats `'lifetimes` as a single token.
    pub(crate) fn skip(self) -> Option<Cursor<'a>> {
        // XXX: Should `skip` enter none-delimited groups?
        match self.entry() {
            Entry::End(..) => None,

            // Treat lifetimes as a single tt for the purposes of 'skip'.
            Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump() };
                match next.entry() {
                    Entry::Ident(_) => Some(unsafe { next.bump() }),
                    _ => Some(next),
                }
            }
            _ => Some(unsafe { self.bump() }),
        }
    }
}

pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
    a.scope == b.scope
}

pub(crate) fn open_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_open(),
        _ => cursor.span(),
    }
}

pub(crate) fn close_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_close(),
        _ => cursor.span(),
    }
}
<commit_msg>Remove question from Cursor::skip<commit_after>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

// This module is heavily commented as it contains most of the unsafe code in
// Syn, and caution should be used when editing it. The public-facing interface
// is 100% safe but the implementation is fragile internally.

#[cfg(all(
    not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
    feature = "proc-macro"
))]
use crate::proc_macro as pm;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};

use std::marker::PhantomData;
use std::ptr;

use crate::Lifetime;

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
enum Entry {
    // Mimicking types from proc-macro.
    Group(Group, TokenBuffer),
    Ident(Ident),
    Punct(Punct),
    Literal(Literal),
    // End entries contain a raw pointer to the entry from the containing
    // token tree, or null if this is the outermost level.
    End(*const Entry),
}

/// A buffer that can be efficiently traversed multiple times, unlike
/// `TokenStream` which requires a deep copy in order to traverse more than
/// once.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not derive clone on this - there are raw pointers inside which
    // will be messed up. Moving the `TokenBuffer` itself is safe as the actual
    // backing slices won't be moved.
    data: Box<[Entry]>,
}

impl TokenBuffer {
    // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
    // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
    fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
        // Build up the entries list, recording the locations of any Groups
        // in the list to be processed later.
        let mut entries = Vec::new();
        let mut seqs = Vec::new();
        for tt in stream {
            match tt {
                TokenTree::Ident(sym) => {
                    entries.push(Entry::Ident(sym));
                }
                TokenTree::Punct(op) => {
                    entries.push(Entry::Punct(op));
                }
                TokenTree::Literal(l) => {
                    entries.push(Entry::Literal(l));
                }
                TokenTree::Group(g) => {
                    // Record the index of the interesting entry, and store an
                    // `End(null)` there temporarially.
                    seqs.push((entries.len(), g));
                    entries.push(Entry::End(ptr::null()));
                }
            }
        }
        // Add an `End` entry to the end with a reference to the enclosing token
        // stream which was passed in.
        entries.push(Entry::End(up));

        // NOTE: This is done to ensure that we don't accidentally modify the
        // length of the backing buffer. The backing buffer must remain at a
        // constant address after this point, as we are going to store a raw
        // pointer into it.
        let mut entries = entries.into_boxed_slice();
        for (idx, group) in seqs {
            // We know that this index refers to one of the temporary
            // `End(null)` entries, and we know that the last entry is
            // `End(up)`, so the next index is also valid.
            let seq_up = &entries[idx + 1] as *const Entry;

            // The end entry stored at the end of this Entry::Group should
            // point to the Entry which follows the Group in the list.
            let inner = Self::inner_new(group.stream(), seq_up);
            entries[idx] = Entry::Group(group, inner);
        }

        TokenBuffer { data: entries }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    ///
    /// *This method is available if Syn is built with both the `"parsing"` and
    /// `"proc-macro"` features.*
    #[cfg(all(
        not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
        feature = "proc-macro"
    ))]
    pub fn new(stream: pm::TokenStream) -> TokenBuffer {
        Self::new2(stream.into())
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    pub fn new2(stream: TokenStream) -> TokenBuffer {
        Self::inner_new(stream, ptr::null())
    }

    /// Creates a cursor referencing the first token in the buffer and able to
    /// traverse until the end of the buffer.
    pub fn begin(&self) -> Cursor {
        unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
    }
}

/// A cheaply copyable cursor into a `TokenBuffer`.
///
/// This cursor holds a shared reference into the immutable data which is used
/// internally to represent a `TokenStream`, and can be efficiently manipulated
/// and copied around.
///
/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
/// object and get a cursor to its first token with `begin()`.
///
/// Two cursors are equal if they have the same location in the same input
/// stream, and have the same scope.
///
/// *This type is available if Syn is built with the `"parsing"` feature.*
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Cursor<'a> {
    // The current entry which the `Cursor` is pointing at.
    ptr: *const Entry,
    // This is the only `Entry::End(..)` object which this cursor is allowed to
    // point at. All other `End` objects are skipped over in `Cursor::create`.
    scope: *const Entry,
    // Cursor is covariant in 'a. This field ensures that our pointers are still
    // valid.
    marker: PhantomData<&'a Entry>,
}

impl<'a> Cursor<'a> {
    /// Creates a cursor referencing a static empty TokenStream.
    pub fn empty() -> Self {
        // It's safe in this situation for us to put an `Entry` object in global
        // storage, despite it not actually being safe to send across threads
        // (`Ident` is a reference into a thread-local table). This is because
        // this entry never includes a `Ident` object.
        //
        // This wrapper struct allows us to break the rules and put a `Sync`
        // object in global storage.
        struct UnsafeSyncEntry(Entry);
        unsafe impl Sync for UnsafeSyncEntry {}
        static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));

        Cursor {
            ptr: &EMPTY_ENTRY.0,
            scope: &EMPTY_ENTRY.0,
            marker: PhantomData,
        }
    }

    /// This create method intelligently exits non-explicitly-entered
    /// `None`-delimited scopes when the cursor reaches the end of them,
    /// allowing for them to be treated transparently.
    unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
        // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
        // past it, unless `ptr == scope`, which means that we're at the edge of
        // our cursor's scope. We should only have `ptr != scope` at the exit
        // from None-delimited groups entered with `ignore_none`.
        while let Entry::End(exit) = *ptr {
            if ptr == scope {
                break;
            }
            ptr = exit;
        }

        Cursor {
            ptr,
            scope,
            marker: PhantomData,
        }
    }

    /// Get the current entry.
    fn entry(self) -> &'a Entry {
        unsafe { &*self.ptr }
    }

    /// Bump the cursor to point at the next token after the current one. This
    /// is undefined behavior if the cursor is currently looking at an
    /// `Entry::End`.
    unsafe fn bump(self) -> Cursor<'a> {
        Cursor::create(self.ptr.offset(1), self.scope)
    }

    /// If the cursor is looking at a `None`-delimited group, move it to look at
    /// the first token inside instead. If the group is empty, this will move
    /// the cursor past the `None`-delimited group.
    ///
    /// WARNING: This mutates its argument.
    fn ignore_none(&mut self) {
        if let Entry::Group(group, buf) = self.entry() {
            if group.delimiter() == Delimiter::None {
                // NOTE: We call `Cursor::create` here to make sure that
                // situations where we should immediately exit the span after
                // entering it are handled correctly.
                unsafe {
                    *self = Cursor::create(&buf.data[0], self.scope);
                }
            }
        }
    }

    /// Checks whether the cursor is currently pointing at the end of its valid
    /// scope.
    pub fn eof(self) -> bool {
        // We're at eof if we're at the end of our scope.
        self.ptr == self.scope
    }

    /// If the cursor is pointing at a `Group` with the given delimiter, returns
    /// a cursor into that group and one pointing to the next `TokenTree`.
    pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
        // If we're not trying to enter a none-delimited group, we want to
        // ignore them. We have to make sure to _not_ ignore them when we want
        // to enter them, of course. For obvious reasons.
        if delim != Delimiter::None {
            self.ignore_none();
        }

        if let Entry::Group(group, buf) = self.entry() {
            if group.delimiter() == delim {
                return Some((buf.begin(), group.span(), unsafe { self.bump() }));
            }
        }

        None
    }

    /// If the cursor is pointing at a `Ident`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at an `Punct`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(op) if op.as_char() != '\'' => Some((op.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Literal`, return it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Literal(lit) => Some((lit.clone(), unsafe { self.bump() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Lifetime`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump() };
                match next.ident() {
                    Some((ident, rest)) => {
                        let lifetime = Lifetime {
                            apostrophe: op.span(),
                            ident,
                        };
                        Some((lifetime, rest))
                    }
                    None => None,
                }
            }
            _ => None,
        }
    }

    /// Copies all remaining tokens visible from this cursor into a
    /// `TokenStream`.
    pub fn token_stream(self) -> TokenStream {
        let mut tts = Vec::new();
        let mut cursor = self;
        while let Some((tt, rest)) = cursor.token_tree() {
            tts.push(tt);
            cursor = rest;
        }
        tts.into_iter().collect()
    }

    /// If the cursor is pointing at a `TokenTree`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    ///
    /// Returns `None` if the cursor has reached the end of its stream.
    ///
    /// This method does not treat `None`-delimited groups as transparent, and
    /// will return a `Group(None, ..)` if the cursor is looking at one.
    pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
        let tree = match self.entry() {
            Entry::Group(group, _) => group.clone().into(),
            Entry::Literal(lit) => lit.clone().into(),
            Entry::Ident(ident) => ident.clone().into(),
            Entry::Punct(op) => op.clone().into(),
            Entry::End(..) => {
                return None;
            }
        };

        Some((tree, unsafe { self.bump() }))
    }

    /// Returns the `Span` of the current token, or `Span::call_site()` if this
    /// cursor points to eof.
    pub fn span(self) -> Span {
        match self.entry() {
            Entry::Group(group, _) => group.span(),
            Entry::Literal(l) => l.span(),
            Entry::Ident(t) => t.span(),
            Entry::Punct(o) => o.span(),
            Entry::End(..) => Span::call_site(),
        }
    }

    /// Skip over the next token without cloning it. Returns `None` if this
    /// cursor points to eof.
    ///
    /// This method treats `'lifetimes` as a single token.
    pub(crate) fn skip(self) -> Option<Cursor<'a>> {
        match self.entry() {
            Entry::End(..) => None,

            // Treat lifetimes as a single tt for the purposes of 'skip'.
            Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump() };
                match next.entry() {
                    Entry::Ident(_) => Some(unsafe { next.bump() }),
                    _ => Some(next),
                }
            }
            _ => Some(unsafe { self.bump() }),
        }
    }
}

pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
    a.scope == b.scope
}

pub(crate) fn open_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_open(),
        _ => cursor.span(),
    }
}

pub(crate) fn close_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_close(),
        _ => cursor.span(),
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate futures;

use futures::{
    executor::block_on,
    future::{self, FutureExt},
    task::Poll,
};

#[test]
fn ready() {
    block_on(future::poll_fn(|_| {
        ready!(Poll::Ready(()),);
        Poll::Ready(())
    }))
}

#[test]
fn poll() {
    block_on(async {
        let _ = poll!(async {}.boxed(),);
    })
}

#[test]
fn join() {
    block_on(async {
        let future1 = async { 1 };
        let future2 = async { 2 };
        join!(future1, future2,);
    })
}

#[test]
fn try_join() {
    block_on(async {
        let future1 = async { 1 }.never_error();
        let future2 = async { 2 }.never_error();
        try_join!(future1, future2,)
    })
    .unwrap();
}
<commit_msg>futures: tests/macro_comma_support.rs: Don't break w/o features<commit_after>#[cfg(feature = "executor")]
#[test]
fn ready() {
    use futures::{
        executor::block_on,
        future,
        task::Poll,
        ready,
    };

    block_on(future::poll_fn(|_| {
        ready!(Poll::Ready(()),);
        Poll::Ready(())
    }))
}

#[cfg(all(feature = "executor", feature = "async-await"))]
#[test]
fn poll() {
    use futures::{
        executor::block_on,
        future::FutureExt,
        poll,
    };

    block_on(async {
        let _ = poll!(async {}.boxed(),);
    })
}

#[cfg(all(feature = "executor", feature = "async-await"))]
#[test]
fn join() {
    use futures::{
        executor::block_on,
        join
    };

    block_on(async {
        let future1 = async { 1 };
        let future2 = async { 2 };
        join!(future1, future2,);
    })
}

#[cfg(all(feature = "executor", feature = "async-await"))]
#[test]
fn try_join() {
    use futures::{
        executor::block_on,
        future::FutureExt,
        try_join,
    };

    block_on(async {
        let future1 = async { 1 }.never_error();
        let future2 = async { 2 }.never_error();
        try_join!(future1, future2,)
    })
    .unwrap();
}
<|endoftext|>


<commit_before>#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    let _ = serde_yaml::from_slice::<serde_yaml::Value>(data);
});
<commit_msg>Limit fuzzer input to 10K<commit_after>#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
    let data = data.get(..10240).unwrap_or(data);
    let _ = serde_yaml::from_slice::<serde_yaml::Value>(data);
});
<|endoftext|>


<commit_before>use nalgebra::{Quaternion, Rotate, ToHomogeneous, Unit, UnitQuaternion, Vector3};
use serde::Deserialize;
use serde_json::from_reader;
use std::default::Default;
use std::f32::consts::FRAC_PI_4;
use std::fs::File;
use std::path::Path;

use projection::{Projectable, perspective};
use resource::{Cache, Load, LoadError};
use transform::{Axis, M44, Orientation, Position, Transformable, Translation, X_AXIS, Y_AXIS,
                Z_AXIS, translation_matrix};

#[derive(Clone, Debug)]
pub struct Camera<P> {
  pub position: Position,
  pub orientation: Orientation,
  pub properties: P
}

impl<P> Camera<P> {
  pub fn new(position: Position, orientation: Orientation, properties: P) -> Self {
    Camera {
      position: position,
      orientation: orientation,
      properties: properties
    }
  }
}

impl<P> Default for Camera<P> where P: Default {
  fn default() -> Self {
    Camera::new(Position::new(0., 0., 0.),
                Orientation::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
                P::default())
  }
}

impl<P> Transformable for Camera<P> {
  fn transform(&self) -> M44 {
    let m = self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(-self.position);
    m.as_ref().clone()
  }
}

#[derive(Deserialize)]
struct Manifest<P> {
  position: [f32; 3],
  orientation: [f32; 4],
  #[serde(default)]
  properties: P
}

impl<'a, A> Load<'a> for Camera<A> where A: Default + Deserialize {
  type Args = ();

  fn load<P>(path: P, _: &mut Cache<'a>, _: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading camera {:?}", path);

    let manifest: Manifest<A> = {
      let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    Ok(Camera {
      position: (&manifest.position).into(),
      orientation: Unit::new(&Quaternion::from(&manifest.orientation)),
      properties: manifest.properties
    })
  }
}

#[derive(Clone, Debug, Deserialize)]
pub struct Freefly {
  // sensitivities
  pub yaw_sens: f32,
  pub pitch_sens: f32,
  pub roll_sens: f32,
  pub forward_sens: f32,
  pub strafe_sens: f32,
  pub upward_sens: f32,
  // projection
  pub ratio: f32,
  pub fovy: f32,
  // clipping
  pub znear: f32,
  pub zfar: f32,
}

impl Freefly {
  pub fn new() -> Self {
    Freefly {
      yaw_sens: 0.01,
      pitch_sens: 0.01,
      roll_sens: 0.01,
      forward_sens: 0.1,
      strafe_sens: 0.1,
      upward_sens: 0.1,
      ratio: 4. / 3.,
      fovy: FRAC_PI_4,
      znear: 0.1,
      zfar: 10.,
    }
  }
}

impl Default for Freefly {
  fn default() -> Self {
    Self::new()
  }
}

impl Projectable for Freefly {
  fn projection(&self) -> M44 {
    perspective(self.ratio, self.fovy, self.znear, self.zfar)
  }
}

impl Camera<Freefly> {
  pub fn mv(&mut self, dir: Translation) {
    let p = &self.properties;
    let axis = dir * Axis::new(p.strafe_sens, p.upward_sens, p.forward_sens);
    let v = self.orientation.inverse_rotate(&axis);

    self.position -= v;
  }

  pub fn look_around(&mut self, dir: Translation) {
    let p = &self.properties;

    fn orient(axis: &Axis, phi: f32) -> Orientation {
      UnitQuaternion::from_axisangle(Unit::new(&axis), phi)
    }

    self.orientation = orient(&Y_AXIS, p.yaw_sens * dir.y) * self.orientation;
    self.orientation = orient(&X_AXIS, p.pitch_sens * dir.x) * self.orientation;
    self.orientation = orient(&Z_AXIS, p.roll_sens * dir.z) * self.orientation;
  }
}
<commit_msg>Default value for all Freefly fields.<commit_after>use nalgebra::{Quaternion, Rotate, ToHomogeneous, Unit, UnitQuaternion, Vector3};
use serde::Deserialize;
use serde_json::from_reader;
use std::default::Default;
use std::f32::consts::FRAC_PI_4;
use std::fs::File;
use std::path::Path;

use projection::{Projectable, perspective};
use resource::{Cache, Load, LoadError};
use transform::{Axis, M44, Orientation, Position, Transformable, Translation, X_AXIS, Y_AXIS,
                Z_AXIS, translation_matrix};

#[derive(Clone, Debug)]
pub struct Camera<P> {
  pub position: Position,
  pub orientation: Orientation,
  pub properties: P
}

impl<P> Camera<P> {
  pub fn new(position: Position, orientation: Orientation, properties: P) -> Self {
    Camera {
      position: position,
      orientation: orientation,
      properties: properties
    }
  }
}

impl<P> Default for Camera<P> where P: Default {
  fn default() -> Self {
    Camera::new(Position::new(0., 0., 0.),
                Orientation::from_unit_value_unchecked(Quaternion::from_parts(1., Vector3::new(0., 0., 0.))),
                P::default())
  }
}

impl<P> Transformable for Camera<P> {
  fn transform(&self) -> M44 {
    let m = self.orientation.to_rotation_matrix().to_homogeneous() * translation_matrix(-self.position);
    m.as_ref().clone()
  }
}

#[derive(Deserialize)]
struct Manifest<P> {
  position: [f32; 3],
  orientation: [f32; 4],
  #[serde(default)]
  properties: P
}

impl<'a, A> Load<'a> for Camera<A> where A: Default + Deserialize {
  type Args = ();

  fn load<P>(path: P, _: &mut Cache<'a>, _: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading camera {:?}", path);

    let manifest: Manifest<A> = {
      let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    Ok(Camera {
      position: (&manifest.position).into(),
      orientation: Unit::new(&Quaternion::from(&manifest.orientation)),
      properties: manifest.properties
    })
  }
}

#[derive(Clone, Debug, Deserialize)]
pub struct Freefly {
  // sensitivities
  #[serde(default = "def_yaw_sens")]
  pub yaw_sens: f32,
  #[serde(default = "def_pitch_sens")]
  pub pitch_sens: f32,
  #[serde(default = "def_roll_sens")]
  pub roll_sens: f32,
  #[serde(default = "def_forward_sens")]
  pub forward_sens: f32,
  #[serde(default = "def_strafe_sens")]
  pub strafe_sens: f32,
  #[serde(default = "def_upward_sens")]
  pub upward_sens: f32,
  // projection
  #[serde(default = "def_ratio")]
  pub ratio: f32,
  #[serde(default = "def_fovy")]
  pub fovy: f32,
  // clipping
  #[serde(default = "def_znear")]
  pub znear: f32,
  #[serde(default = "def_zfar")]
  pub zfar: f32,
}

impl Freefly {
  pub fn new() -> Self {
    Freefly {
      yaw_sens: def_yaw_sens(),
      pitch_sens: def_pitch_sens(),
      roll_sens: def_roll_sens(),
      forward_sens: def_forward_sens(),
      strafe_sens: def_strafe_sens(),
      upward_sens: def_upward_sens(),
      ratio: def_ratio(),
      fovy: def_fovy(),
      znear: def_znear(),
      zfar: def_zfar(),
    }
  }
}

impl Default for Freefly {
  fn default() -> Self {
    Self::new()
  }
}

impl Projectable for Freefly {
  fn projection(&self) -> M44 {
    perspective(self.ratio, self.fovy, self.znear, self.zfar)
  }
}

impl Camera<Freefly> {
  pub fn mv(&mut self, dir: Translation) {
    let p = &self.properties;
    let axis = dir * Axis::new(p.strafe_sens, p.upward_sens, p.forward_sens);
    let v = self.orientation.inverse_rotate(&axis);

    self.position -= v;
  }

  pub fn look_around(&mut self, dir: Translation) {
    let p = &self.properties;

    fn orient(axis: &Axis, phi: f32) -> Orientation {
      UnitQuaternion::from_axisangle(Unit::new(&axis), phi)
    }

    self.orientation = orient(&Y_AXIS, p.yaw_sens * dir.y) * self.orientation;
    self.orientation = orient(&X_AXIS, p.pitch_sens * dir.x) * self.orientation;
    self.orientation = orient(&Z_AXIS, p.roll_sens * dir.z) * self.orientation;
  }
}

fn def_yaw_sens() -> f32 { 0.01 }
fn def_pitch_sens() -> f32 { 0.01 }
fn def_roll_sens() -> f32 { 0.01 }
fn def_forward_sens() -> f32 { 0.1 }
fn def_strafe_sens() -> f32 { 0.1 }
fn def_upward_sens() -> f32 { 0.1 }
fn def_ratio() -> f32 { 4. / 3. }
fn def_fovy() -> f32 { FRAC_PI_4 }
fn def_znear() -> f32 { 0.1 }
fn def_zfar() -> f32 { 10. }
<|endoftext|>


<commit_before>//! Utilities for building protocol clients
//!
//! Provides a channel that handles details of providing a `Service` client.
//! Usually, this module does not have to be used directly. Instead it is used
//! by `pipeline` and `multiplex` in the `connect` fns.
//!
//! However, some protocols require implementing the dispatch layer directly,
//! in which case using client channel is helpful.

// Allow warnings in order to prevent the compiler from outputting an error
// that seems to be fixed on nightly.
#![allow(warnings)]

use {Error, Message};
use sender::Sender;
use tokio_service::Service;
use futures::stream::{self, Stream};
use futures::{self, Future, Oneshot, Complete, Async, Poll};
use std::io;
use std::cell::RefCell;

/// Client `Service` for pipeline or multiplex protocols
pub struct Client<R1, R2, B1, B2, E>
    where B1: Stream<Error = E>,
          E: From<Error<E>>,
{
    tx: RefCell<Sender<Envelope<R1, R2, B1, B2, E>, io::Error>>,
}

/// Response future returned from a client
pub struct Response<T, E> {
    inner: Oneshot<Result<T, E>>,
}

/// Message used to dispatch requests to the task managing the client
/// connection.
type Envelope<R1, R2, B1, B2, E> =
    (Message<R1, B1>, Complete<Result<Message<R2, B2>, E>>);

/// A client / receiver pair
pub type Pair<R1, R2, B1, B2, E> =
    (Client<R1, R2, B1, B2, E>, Receiver<R1, R2, B1, B2, E>);

/// Receive requests submitted to the client
pub type Receiver<R1, R2, B1, B2, E> =
    stream::Receiver<Envelope<R1, R2, B1, B2, E>, io::Error>;

/// Return a client handle and a handle used to receive requests on
pub fn pair<R1, R2, B1, B2, E>() -> Pair<R1, R2, B1, B2, E>
    where B1: Stream<Error = E>,
          E: From<Error<E>>,
{
    // Create a stream
    let (tx, rx) = stream::channel();

    // Use the sender handle to create a `Client` handle
    let client = Client { tx: RefCell::new(tx.into()) };

    // Return the pair
    (client, rx)
}

impl<R1, R2, B1, B2, E> Service for Client<R1, R2, B1, B2, E>
    where R1: 'static,
          R2: 'static,
          B1: Stream<Error = E> + 'static,
          B2: 'static,
          E: From<Error<E>> + 'static,
{
    type Request = Message<R1, B1>;
    type Response = Message<R2, B2>;
    type Error = E;
    type Future = Response<Self::Response, E>;

    fn call(&self, request: Self::Request) -> Self::Future {
        let (tx, rx) = futures::oneshot();

        // TODO: handle error
        self.tx.borrow_mut().send(Ok((request, tx)));

        Response { inner: rx }
    }

    fn poll_ready(&self) -> Async<()> {
        self.tx.borrow_mut().poll_ready().unwrap()
    }
}

impl<T, E> Future for Response<T, E> {
    type Item = T;
    type Error = E;

    fn poll(&mut self) -> Poll<T, E> {
        match self.inner.poll() {
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(_) => panic!("aborted"),
        }
    }
}
<commit_msg>Include error when panicking in client response<commit_after>//! Utilities for building protocol clients
//!
//! Provides a channel that handles details of providing a `Service` client.
//! Usually, this module does not have to be used directly. Instead it is used
//! by `pipeline` and `multiplex` in the `connect` fns.
//!
//! However, some protocols require implementing the dispatch layer directly,
//! in which case using client channel is helpful.

// Allow warnings in order to prevent the compiler from outputting an error
// that seems to be fixed on nightly.
#![allow(warnings)]

use {Error, Message};
use sender::Sender;
use tokio_service::Service;
use futures::stream::{self, Stream};
use futures::{self, Future, Oneshot, Complete, Async, Poll};
use std::io;
use std::cell::RefCell;

/// Client `Service` for pipeline or multiplex protocols
pub struct Client<R1, R2, B1, B2, E>
    where B1: Stream<Error = E>,
          E: From<Error<E>>,
{
    tx: RefCell<Sender<Envelope<R1, R2, B1, B2, E>, io::Error>>,
}

/// Response future returned from a client
pub struct Response<T, E> {
    inner: Oneshot<Result<T, E>>,
}

/// Message used to dispatch requests to the task managing the client
/// connection.
type Envelope<R1, R2, B1, B2, E> =
    (Message<R1, B1>, Complete<Result<Message<R2, B2>, E>>);

/// A client / receiver pair
pub type Pair<R1, R2, B1, B2, E> =
    (Client<R1, R2, B1, B2, E>, Receiver<R1, R2, B1, B2, E>);

/// Receive requests submitted to the client
pub type Receiver<R1, R2, B1, B2, E> =
    stream::Receiver<Envelope<R1, R2, B1, B2, E>, io::Error>;

/// Return a client handle and a handle used to receive requests on
pub fn pair<R1, R2, B1, B2, E>() -> Pair<R1, R2, B1, B2, E>
    where B1: Stream<Error = E>,
          E: From<Error<E>>,
{
    // Create a stream
    let (tx, rx) = stream::channel();

    // Use the sender handle to create a `Client` handle
    let client = Client { tx: RefCell::new(tx.into()) };

    // Return the pair
    (client, rx)
}

impl<R1, R2, B1, B2, E> Service for Client<R1, R2, B1, B2, E>
    where R1: 'static,
          R2: 'static,
          B1: Stream<Error = E> + 'static,
          B2: 'static,
          E: From<Error<E>> + 'static,
{
    type Request = Message<R1, B1>;
    type Response = Message<R2, B2>;
    type Error = E;
    type Future = Response<Self::Response, E>;

    fn call(&self, request: Self::Request) -> Self::Future {
        let (tx, rx) = futures::oneshot();

        // TODO: handle error
        self.tx.borrow_mut().send(Ok((request, tx)));

        Response { inner: rx }
    }

    fn poll_ready(&self) -> Async<()> {
        self.tx.borrow_mut().poll_ready().unwrap()
    }
}

impl<T, E> Future for Response<T, E> {
    type Item = T;
    type Error = E;

    fn poll(&mut self) -> Poll<T, E> {
        match self.inner.poll() {
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            // TODO: This can happen if the connection failed to establish
            Err(e) => panic!("aborted: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

//! This program implements a rustc driver that retrieves MIR bodies with
//! borrowck information. This cannot be done in a straightforward way because
//! `get_body_with_borrowck_facts`–the function for retrieving a MIR body with
//! borrowck facts–can panic if the body is stolen before it is invoked.
//! Therefore, the driver overrides `mir_borrowck` query (this is done in the
//! `config` callback), which retrieves the body that is about to be borrow
//! checked and stores it in a thread local `MIR_BODIES`. Then, `after_analysis`
//! callback triggers borrow checking of all MIR bodies by retrieving
//! `optimized_mir` and pulls out the MIR bodies with the borrowck information
//! from the thread local storage.

extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_mir;
extern crate rustc_session;

use rustc_driver::Compilation;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_interface::interface::Compiler;
use rustc_interface::{Config, Queries};
use rustc_middle::ty::query::query_values::mir_borrowck;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_mir::consumers::BodyWithBorrowckFacts;
use rustc_session::Session;
use std::cell::RefCell;
use std::collections::HashMap;
use std::thread_local;

fn main() {
    let exit_code = rustc_driver::catch_with_exit_code(move || {
        let mut rustc_args: Vec<_> = std::env::args().collect();
        // We must pass -Zpolonius so that the borrowck information is computed.
        rustc_args.push("-Zpolonius".to_owned());
        let mut callbacks = CompilerCalls::default();
        // Call the Rust compiler with our callbacks.
        rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run()
    });
    std::process::exit(exit_code);
}

#[derive(Default)]
pub struct CompilerCalls;

impl rustc_driver::Callbacks for CompilerCalls {

    // In this callback we override the mir_borrowck query.
    fn config(&mut self, config: &mut Config) {
        assert!(config.override_queries.is_none());
        config.override_queries = Some(override_queries);
    }

    // In this callback we trigger borrow checking of all functions and obtain
    // the result.
    fn after_analysis<'tcx>(
        &mut self,
        compiler: &Compiler,
        queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
        compiler.session().abort_if_errors();
        queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {

            // Collect definition ids of MIR bodies.
            let hir = tcx.hir();
            let krate = hir.krate();
            let mut visitor = HirVisitor { bodies: Vec::new() };
            krate.visit_all_item_likes(&mut visitor);

            // Trigger borrow checking of all bodies.
            for def_id in visitor.bodies {
                let _ = tcx.optimized_mir(def_id);
            }

            // See what bodies were borrow checked.
            let mut bodies = get_bodies(tcx);
            bodies.sort_by(|(def_id1, _), (def_id2, _)| def_id1.cmp(def_id2));
            println!("Bodies retrieved for:");
            for (def_id, body) in bodies {
                println!("{}", def_id);
                assert!(body.input_facts.cfg_edge.len() > 0);
            }
        });

        Compilation::Continue
    }
}

fn override_queries(_session: &Session, local: &mut Providers, external: &mut Providers) {
    local.mir_borrowck = mir_borrowck;
    external.mir_borrowck = mir_borrowck;
}

// Since mir_borrowck does not have access to any other state, we need to use a
// thread-local for storing the obtained MIR bodies.
//
// Note: We are using 'static lifetime here, which is in general unsound.
// Unfortunately, that is the only lifetime allowed here. Our use is safe
// because we cast it back to `'tcx` before using.
thread_local! {
    pub static MIR_BODIES:
        RefCell<HashMap<LocalDefId, BodyWithBorrowckFacts<'static>>> =
        RefCell::new(HashMap::new());
}

fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tcx> {
    let body_with_facts = rustc_mir::consumers::get_body_with_borrowck_facts(
        tcx,
        ty::WithOptConstParam::unknown(def_id),
    );
    // SAFETY: The reader casts the 'static lifetime to 'tcx before using it.
    let body_with_facts: BodyWithBorrowckFacts<'static> =
        unsafe { std::mem::transmute(body_with_facts) };
    MIR_BODIES.with(|state| {
        let mut map = state.borrow_mut();
        assert!(map.insert(def_id, body_with_facts).is_none());
    });
    let mut providers = Providers::default();
    rustc_mir::provide(&mut providers);
    let original_mir_borrowck = providers.mir_borrowck;
    original_mir_borrowck(tcx, def_id)
}

/// Visitor that collects all body definition ids mentioned in the program.
struct HirVisitor {
    bodies: Vec<LocalDefId>,
}

impl<'tcx> ItemLikeVisitor<'tcx> for HirVisitor {
    fn visit_item(&mut self, item: &rustc_hir::Item) {
        if let rustc_hir::ItemKind::Fn(..) = item.kind {
            self.bodies.push(item.def_id);
        }
    }

    fn visit_trait_item(&mut self, trait_item: &rustc_hir::TraitItem) {
        if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
            if let rustc_hir::TraitFn::Provided(_) = trait_fn {
                self.bodies.push(trait_item.def_id);
            }
        }
    }

    fn visit_impl_item(&mut self, impl_item: &rustc_hir::ImplItem) {
        if let rustc_hir::ImplItemKind::Fn(..) = impl_item.kind {
            self.bodies.push(impl_item.def_id);
        }
    }

    fn visit_foreign_item(&mut self, _foreign_item: &rustc_hir::ForeignItem) {}
}

/// Pull MIR bodies stored in the thread-local.
fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> {
    MIR_BODIES.with(|state| {
        let mut map = state.borrow_mut();
        map.drain()
            .map(|(def_id, body)| {
                let def_path = tcx.def_path(def_id.to_def_id());
                // SAFETY: For soundness we need to ensure that the bodies have
                // the same lifetime (`'tcx`), which they had before they were
                // stored in the thread local.
                (def_path.to_string_no_crate_verbose(), body)
            })
            .collect()
    })
}
<commit_msg>Update run-make-fulldeps.<commit_after>#![feature(rustc_private)]

//! This program implements a rustc driver that retrieves MIR bodies with
//! borrowck information. This cannot be done in a straightforward way because
//! `get_body_with_borrowck_facts`–the function for retrieving a MIR body with
//! borrowck facts–can panic if the body is stolen before it is invoked.
//! Therefore, the driver overrides `mir_borrowck` query (this is done in the
//! `config` callback), which retrieves the body that is about to be borrow
//! checked and stores it in a thread local `MIR_BODIES`. Then, `after_analysis`
//! callback triggers borrow checking of all MIR bodies by retrieving
//! `optimized_mir` and pulls out the MIR bodies with the borrowck information
//! from the thread local storage.

extern crate rustc_borrowck;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate rustc_session;

use rustc_borrowck::consumers::BodyWithBorrowckFacts;
use rustc_driver::Compilation;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_interface::interface::Compiler;
use rustc_interface::{Config, Queries};
use rustc_middle::ty::query::query_values::mir_borrowck;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
use std::cell::RefCell;
use std::collections::HashMap;
use std::thread_local;

fn main() {
    let exit_code = rustc_driver::catch_with_exit_code(move || {
        let mut rustc_args: Vec<_> = std::env::args().collect();
        // We must pass -Zpolonius so that the borrowck information is computed.
        rustc_args.push("-Zpolonius".to_owned());
        let mut callbacks = CompilerCalls::default();
        // Call the Rust compiler with our callbacks.
        rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run()
    });
    std::process::exit(exit_code);
}

#[derive(Default)]
pub struct CompilerCalls;

impl rustc_driver::Callbacks for CompilerCalls {

    // In this callback we override the mir_borrowck query.
    fn config(&mut self, config: &mut Config) {
        assert!(config.override_queries.is_none());
        config.override_queries = Some(override_queries);
    }

    // In this callback we trigger borrow checking of all functions and obtain
    // the result.
    fn after_analysis<'tcx>(
        &mut self,
        compiler: &Compiler,
        queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
        compiler.session().abort_if_errors();
        queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {

            // Collect definition ids of MIR bodies.
            let hir = tcx.hir();
            let krate = hir.krate();
            let mut visitor = HirVisitor { bodies: Vec::new() };
            krate.visit_all_item_likes(&mut visitor);

            // Trigger borrow checking of all bodies.
            for def_id in visitor.bodies {
                let _ = tcx.optimized_mir(def_id);
            }

            // See what bodies were borrow checked.
            let mut bodies = get_bodies(tcx);
            bodies.sort_by(|(def_id1, _), (def_id2, _)| def_id1.cmp(def_id2));
            println!("Bodies retrieved for:");
            for (def_id, body) in bodies {
                println!("{}", def_id);
                assert!(body.input_facts.cfg_edge.len() > 0);
            }
        });

        Compilation::Continue
    }
}

fn override_queries(_session: &Session, local: &mut Providers, external: &mut Providers) {
    local.mir_borrowck = mir_borrowck;
    external.mir_borrowck = mir_borrowck;
}

// Since mir_borrowck does not have access to any other state, we need to use a
// thread-local for storing the obtained MIR bodies.
//
// Note: We are using 'static lifetime here, which is in general unsound.
// Unfortunately, that is the only lifetime allowed here. Our use is safe
// because we cast it back to `'tcx` before using.
thread_local! {
    pub static MIR_BODIES:
        RefCell<HashMap<LocalDefId, BodyWithBorrowckFacts<'static>>> =
        RefCell::new(HashMap::new());
}

fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tcx> {
    let body_with_facts = rustc_borrowck::consumers::get_body_with_borrowck_facts(
        tcx,
        ty::WithOptConstParam::unknown(def_id),
    );
    // SAFETY: The reader casts the 'static lifetime to 'tcx before using it.
    let body_with_facts: BodyWithBorrowckFacts<'static> =
        unsafe { std::mem::transmute(body_with_facts) };
    MIR_BODIES.with(|state| {
        let mut map = state.borrow_mut();
        assert!(map.insert(def_id, body_with_facts).is_none());
    });
    let mut providers = Providers::default();
    rustc_borrowck::provide(&mut providers);
    let original_mir_borrowck = providers.mir_borrowck;
    original_mir_borrowck(tcx, def_id)
}

/// Visitor that collects all body definition ids mentioned in the program.
struct HirVisitor {
    bodies: Vec<LocalDefId>,
}

impl<'tcx> ItemLikeVisitor<'tcx> for HirVisitor {
    fn visit_item(&mut self, item: &rustc_hir::Item) {
        if let rustc_hir::ItemKind::Fn(..) = item.kind {
            self.bodies.push(item.def_id);
        }
    }

    fn visit_trait_item(&mut self, trait_item: &rustc_hir::TraitItem) {
        if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
            if let rustc_hir::TraitFn::Provided(_) = trait_fn {
                self.bodies.push(trait_item.def_id);
            }
        }
    }

    fn visit_impl_item(&mut self, impl_item: &rustc_hir::ImplItem) {
        if let rustc_hir::ImplItemKind::Fn(..) = impl_item.kind {
            self.bodies.push(impl_item.def_id);
        }
    }

    fn visit_foreign_item(&mut self, _foreign_item: &rustc_hir::ForeignItem) {}
}

/// Pull MIR bodies stored in the thread-local.
fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> {
    MIR_BODIES.with(|state| {
        let mut map = state.borrow_mut();
        map.drain()
            .map(|(def_id, body)| {
                let def_path = tcx.def_path(def_id.to_def_id());
                // SAFETY: For soundness we need to ensure that the bodies have
                // the same lifetime (`'tcx`), which they had before they were
                // stored in the thread local.
                (def_path.to_string_no_crate_verbose(), body)
            })
            .collect()
    })
}
<|endoftext|>


<commit_before>extern crate envy;

use std::env::var;
use std::path::MAIN_SEPARATOR;

static BASE_URL_KEY: &str = "K2_BASE_URL";
static DEFAULT_BASE_URL: &str = "http://localhost:8080/k2/ctapi/";
static LOG_PATH_KEY: &str = "K2_LOG_PATH";

#[derive(Deserialize)]
struct Config {
    #[serde(rename = "k2_ctn")]
    ctn: u16,
    #[serde(rename = "k2_pn")]
    pn: u16,
}

pub fn base_url() -> String {
    let mut url = var(BASE_URL_KEY).unwrap_or(DEFAULT_BASE_URL.to_string());
    if !url.trim().ends_with("/") {
        url.push_str("/");
    }

    url
}

pub fn log_path() -> Option<String> {
    match var(LOG_PATH_KEY) {
        Ok(mut path) => {
            if !path.trim().ends_with(MAIN_SEPARATOR) {
                path.push(MAIN_SEPARATOR);
            }

            Some(path)
        }
        _ => None,
    }
}

pub fn ctn_or(ctn: u16) -> u16 {
    match envy::from_env::<Config>() {
        Ok(config) => {
            info!("CTN from env: {}", config.ctn);
            config.ctn
        }
        _ => ctn,
    }
}

pub fn pn_or(pn: u16) -> u16 {
    match envy::from_env::<Config>() {
        Ok(config) => {
            info!("PN from env: {}", config.pn);
            config.pn
        }
        _ => pn,
    }
}

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

    #[test]
    fn ctn_or_return_env_value_if_pn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 2);
    }

    #[test]
    fn ctn_or_return_given_value_if_pn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);

        env::set_var("K2_CTN", "2");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);
    }

    #[test]
    fn pn_or_return_env_value_if_ctn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let pn = pn_or(1);

        assert_eq!(pn, 4);
    }

    #[test]
    fn pn_or_return_given_value_if_ctn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let pn = pn_or(1);

        assert_eq!(pn, 1);

        env::set_var("K2_PN", "2");
        let pn = pn_or(1);

        assert_eq!(pn, 1);
    }

    #[test]
    fn base_url_return_env_value() {
        env::set_var(BASE_URL_KEY, "a/");
        let url = base_url();

        assert_eq!(url, "a/");

        env::set_var(BASE_URL_KEY, "1");
        let url = base_url();

        assert_eq!(url, "1/");
    }

    #[test]
    fn base_url_return_default_value_if_no_env() {
        env::remove_var(BASE_URL_KEY);
        let url = base_url();

        assert_eq!(url, DEFAULT_BASE_URL);
    }

    #[test]
    fn log_path_returns_env_value() {
        env::set_var(LOG_PATH_KEY, "a");
        let path = log_path();

        assert_eq!(path, Some(String::from("a/")));
    }

    #[test]
    fn log_path_return_none_if_no_env() {
        env::remove_var(LOG_PATH_KEY);
        let path = log_path();

        assert!(path.is_none());
    }
}
<commit_msg>adjuat test to avoid build failure on windows machine<commit_after>extern crate envy;

use std::env::var;
use std::path::MAIN_SEPARATOR;

static BASE_URL_KEY: &str = "K2_BASE_URL";
static DEFAULT_BASE_URL: &str = "http://localhost:8080/k2/ctapi/";
static LOG_PATH_KEY: &str = "K2_LOG_PATH";

#[derive(Deserialize)]
struct Config {
    #[serde(rename = "k2_ctn")]
    ctn: u16,
    #[serde(rename = "k2_pn")]
    pn: u16,
}

pub fn base_url() -> String {
    let mut url = var(BASE_URL_KEY).unwrap_or(DEFAULT_BASE_URL.to_string());
    if !url.trim().ends_with("/") {
        url.push_str("/");
    }

    url
}

pub fn log_path() -> Option<String> {
    match var(LOG_PATH_KEY) {
        Ok(mut path) => {
            if !path.trim().ends_with(MAIN_SEPARATOR) {
                path.push(MAIN_SEPARATOR);
            }

            Some(path)
        }
        _ => None,
    }
}

pub fn ctn_or(ctn: u16) -> u16 {
    match envy::from_env::<Config>() {
        Ok(config) => {
            info!("CTN from env: {}", config.ctn);
            config.ctn
        }
        _ => ctn,
    }
}

pub fn pn_or(pn: u16) -> u16 {
    match envy::from_env::<Config>() {
        Ok(config) => {
            info!("PN from env: {}", config.pn);
            config.pn
        }
        _ => pn,
    }
}

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

    #[test]
    fn ctn_or_return_env_value_if_pn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 2);
    }

    #[test]
    fn ctn_or_return_given_value_if_pn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);

        env::set_var("K2_CTN", "2");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);
    }

    #[test]
    fn pn_or_return_env_value_if_ctn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let pn = pn_or(1);

        assert_eq!(pn, 4);
    }

    #[test]
    fn pn_or_return_given_value_if_ctn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let pn = pn_or(1);

        assert_eq!(pn, 1);

        env::set_var("K2_PN", "2");
        let pn = pn_or(1);

        assert_eq!(pn, 1);
    }

    #[test]
    fn base_url_return_env_value() {
        env::set_var(BASE_URL_KEY, "a/");
        let url = base_url();

        assert_eq!(url, "a/");

        env::set_var(BASE_URL_KEY, "1");
        let url = base_url();

        assert_eq!(url, "1/");
    }

    #[test]
    fn base_url_return_default_value_if_no_env() {
        env::remove_var(BASE_URL_KEY);
        let url = base_url();

        assert_eq!(url, DEFAULT_BASE_URL);
    }

    #[test]
    fn log_path_returns_env_value() {
        env::set_var(LOG_PATH_KEY, "a");
        let path = log_path();

        assert_eq!(path, Some(String::from(format!("a{}", MAIN_SEPARATOR))));
    }

    #[test]
    fn log_path_return_none_if_no_env() {
        env::remove_var(LOG_PATH_KEY);
        let path = log_path();

        assert!(path.is_none());
    }
}
<|endoftext|>