<commit_before>//! TableProperties contains a bunch of read-only properties of its associated
//! table.

use std::os::raw::c_void;
use std::u32;
use std::slice;
use std::str;
use std::fmt;
use std::mem;
use std::marker::PhantomData;

use rocks_sys as ll;

use types::SequenceNumber;
use to_raw::{ToRaw, FromRaw};

pub const UNKNOWN_COLUMN_FAMILY_ID: u32 = u32::MAX;

/// A collections of table properties objects, where
///  key: is the table's file name.
///  value: the table properties object of the given table.
pub struct TablePropertiesCollection {
    // std::unordered_map<std::string, std::shared_ptr<const TableProperties>>
    raw: *mut ll::rocks_table_props_collection_t,
}

impl FromRaw<ll::rocks_table_props_collection_t> for TablePropertiesCollection {
    unsafe fn from_ll(raw: *mut ll::rocks_table_props_collection_t) -> Self {
        TablePropertiesCollection {
            raw: raw
        }
    }
}

impl Drop for TablePropertiesCollection {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_table_props_collection_destroy(self.raw);
        }
    }
}

impl TablePropertiesCollection {
    pub fn len(&self) -> usize {
        unsafe {
            ll::rocks_table_props_collection_size(self.raw) as usize
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn iter<'a>(&'a self) -> TablePropertiesCollectionIter<'a> {
        TablePropertiesCollectionIter {
            raw: unsafe { ll::rocks_table_props_collection_iter_create(self.raw) },
            size: self.len(),
            at_end: self.is_empty(),
            _marker: PhantomData,
        }
    }
}

pub struct TablePropertiesCollectionIter<'a> {
    raw: *mut ll::rocks_table_props_collection_iter_t,
    size: usize,
    at_end: bool,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for TablePropertiesCollectionIter<'a> {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_table_props_collection_iter_destroy(self.raw);
        }
    }
}

impl<'a> Iterator for TablePropertiesCollectionIter<'a> {
    type Item = (String, TableProperties<'a>);

    fn next(&mut self) -> Option<(String, TableProperties<'a>)> {
        if self.raw.is_null() || self.at_end {
            None
        } else {
            unsafe {
                let mut key = String::new();
                ll::rocks_table_props_collection_iter_key(self.raw,
                                                          &mut key as *mut String as *mut c_void);
                let prop = TableProperties::from_ll(ll::rocks_table_props_collection_iter_value(self.raw));
                self.at_end = ll::rocks_table_props_collection_iter_next(self.raw) == 0;
                // FIXME: can't use &str here, since each time iterator->first will be reused
                Some((key, prop))
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

/// Other than basic table properties, each table may also have the user
/// collected properties.
///
/// The value of the user-collected properties are encoded as raw bytes --
/// users have to interprete these values by themselves.
///
/// Rust: wraps, and exposes a `{String => Vec<u8>}` map
#[repr(C)]
#[derive(Debug)]
pub struct UserCollectedProperties {
    // *std::map<std::string, std::string>
    raw: *mut c_void,
}

impl ToRaw<ll::rocks_user_collected_props_t> for UserCollectedProperties {
    fn raw(&self) -> *mut ll::rocks_user_collected_props_t {
        unsafe {
            mem::transmute(self as *const UserCollectedProperties as *mut c_void)
        }
    }
}

impl UserCollectedProperties {
    pub fn insert(&mut self, k: &str, v: &[u8]) {
        unimplemented!()
    }

    pub fn len(&self) -> usize {
        unsafe {
            ll::rocks_user_collected_props_size(self.raw()) as usize
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn iter<'a>(&'a self) -> UserCollectedPropertiesIter<'a> {
        UserCollectedPropertiesIter {
            raw: unsafe { ll::rocks_user_collected_props_iter_create(self.raw()) },
            size: self.len(),
            at_end: self.is_empty(),
            _marker: PhantomData,
        }
    }
}

pub struct UserCollectedPropertiesIter<'a> {
    raw: *mut ll::rocks_user_collected_props_iter_t,
    size: usize,
    at_end: bool,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for UserCollectedPropertiesIter<'a> {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_user_collected_props_iter_destroy(self.raw);
        }
    }
}

impl<'a> Iterator for UserCollectedPropertiesIter<'a> {
    // FIXME: is {String => Vec<u8>} right?
    type Item = (String, Vec<u8>);

    fn next(&mut self) -> Option<(String, Vec<u8>)> {
        if self.raw.is_null() || self.at_end {
            None
        } else {
            unsafe {
                let mut key = String::new();
                ll::rocks_user_collected_props_iter_key(self.raw,
                                                        &mut key as *mut String as *mut c_void);
                let mut value = Vec::new();
                ll::rocks_user_collected_props_iter_value(self.raw,
                                                        &mut value as *mut Vec<u8> as *mut c_void);
                self.at_end = ll::rocks_user_collected_props_iter_next(self.raw) == 0;
                Some((key, value))
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum EntryType {
    EntryPut,
    EntryDelete,
    EntrySingleDelete,
    EntryMerge,
    EntryOther,
}

/// `TablePropertiesCollector` provides the mechanism for users to collect
/// their own properties that they are interested in. This class is essentially
/// a collection of callback functions that will be invoked during table
/// building. It is construced with TablePropertiesCollectorFactory. The methods
/// don't need to be thread-safe, as we will create exactly one
/// TablePropertiesCollector object per table and then call it sequentially
pub trait TablePropertiesCollector {
    /// AddUserKey() will be called when a new key/value pair is inserted into the
    /// table.
    ///
    /// @params key    the user key that is inserted into the table.
    /// @params value  the value that is inserted into the table.
    fn add_user_key(&mut self, key: &[u8],  value: &[u8],
                    type_: EntryType, seq: SequenceNumber,
                    file_size: u64);

    /// Finish() will be called when a table has already been built and is ready
    /// for writing the properties block.
    /// @params properties  User will add their collected statistics to
    /// `properties`.
    fn finish(&mut self, properties: &mut UserCollectedProperties);

    /// The name of the properties collector can be used for debugging purpose.
    fn name(&self) -> &str {
        "RustTablePropertiesCollector\0"
    }

    // fn need_compact(&self) -> bool
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Context {
    column_family_id: u32,
}

// Constructs TablePropertiesCollector. Internals create a new
// TablePropertiesCollector for each new table
pub trait TablePropertiesCollectorFactory {
    fn create_table_properties_collector(&mut self, context: Context) -> Box<TablePropertiesCollector>;

    fn name(&self) -> &str {
        "RustTablePropertiesCollectorFactory\0"
    }
}

/// TableProperties contains a bunch of read-only properties of its associated
/// table.
#[repr(C)]
pub struct TableProperties<'a> {
    raw: *mut ll::rocks_table_props_t,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for TableProperties<'a> {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_table_props_destroy(self.raw);
        }
    }
}

impl<'a> FromRaw<ll::rocks_table_props_t> for TableProperties<'a> {
    unsafe fn from_ll(raw: *mut ll::rocks_table_props_t) -> Self {
        TableProperties {
            raw: raw,
            _marker: PhantomData,
        }
    }
}

impl<'a> fmt::Display for TableProperties<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut ret = String::new();
        unsafe {
            ll::rocks_table_props_to_string(self.raw, &mut ret as *mut String as *mut c_void);
        }
        write!(f, "{}", ret)
    }
}

impl<'a> fmt::Debug for TableProperties<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TableProperties({:?})", self.to_string())
    }
}

impl<'a> TableProperties<'a> {
    // the total size of all data blocks.
    pub fn data_size(&self) -> u64 {
        unsafe {
            ll::rocks_table_props_get_data_size(self.raw)
        }
    }
    // the size of index block.
    pub fn index_size(&self) -> u64 {
        0
    }
    // the size of filter block.
    pub fn filter_size(&self) -> u64 {
        0
    }
    // total raw key size
    pub fn raw_key_size(&self) -> u64 {
        0
    }
    // total raw value size
    pub fn raw_value_size(&self) -> u64 {
        0
    }
    // the number of blocks in this table
    pub fn num_data_blocks(&self) -> u64 {
        0
    }
    // the number of entries in this table
    pub fn num_entries(&self) -> u64 {
        0
    }
    // format version, reserved for backward compatibility
    pub fn format_version(&self) -> u64 {
        0
    }
    // If 0, key is variable length. Otherwise number of bytes for each key.
    pub fn fixed_key_len(&self) -> u64 {
        0
    }
    // ID of column family for this SST file, corresponding to the CF identified
    // by column_family_name.
    pub fn column_family_id(&self) -> u64 {
        0
    }

    // Name of the column family with which this SST file is associated.
    // If column family is unknown, `column_family_name` will be an empty string.
    pub fn column_family_name(&self) -> Option<&str> {
        None
    }

    // The name of the filter policy used in this table.
    // If no filter policy is used, `filter_policy_name` will be an empty string.
    pub fn filter_policy_name(&self) -> Option<&str> {
        None
    }

    // The name of the comparator used in this table.
    pub fn comparator_name(&self) -> &str {
        ""
    }

    // The name of the merge operator used in this table.
    // If no merge operator is used, `merge_operator_name` will be "nullptr".
    pub fn merge_operator_name(&self) -> Option<&str> {
        None
    }

    // The name of the prefix extractor used in this table
    // If no prefix extractor is used, `prefix_extractor_name` will be "nullptr".
    pub fn prefix_extractor_name(&self) -> Option<&str> {
        None
    }

    // The names of the property collectors factories used in this table
    // separated by commas
    // {collector_name[1]},{collector_name[2]},{collector_name[3]} ..
    pub fn property_collectors_names(&self) -> &str {
        ""
    }

    // The compression algo used to compress the SST files.
    pub fn compression_name(&self) -> &str {
        ""
    }

    // user collected properties
    pub fn user_collected_properties(&self) -> &UserCollectedProperties {
        unsafe {
            let raw_ptr = ll::rocks_table_props_get_user_collected_properties(self.raw);
            mem::transmute(raw_ptr)
        }
    }

    pub fn readable_properties(&self) -> &UserCollectedProperties {
        unsafe {
            let raw_ptr = ll::rocks_table_props_get_readable_properties(self.raw);
            mem::transmute(raw_ptr)
        }
    }
}

<commit_msg>table_properties: fix unsafe scope<commit_after>//! TableProperties contains a bunch of read-only properties of its associated
//! table.

use std::os::raw::c_void;
use std::u32;
use std::slice;
use std::str;
use std::fmt;
use std::mem;
use std::marker::PhantomData;

use rocks_sys as ll;

use types::SequenceNumber;
use to_raw::{ToRaw, FromRaw};

pub const UNKNOWN_COLUMN_FAMILY_ID: u32 = u32::MAX;

/// A collections of table properties objects, where
///  key: is the table's file name.
///  value: the table properties object of the given table.
pub struct TablePropertiesCollection {
    // std::unordered_map<std::string, std::shared_ptr<const TableProperties>>
    raw: *mut ll::rocks_table_props_collection_t,
}

impl FromRaw<ll::rocks_table_props_collection_t> for TablePropertiesCollection {
    unsafe fn from_ll(raw: *mut ll::rocks_table_props_collection_t) -> Self {
        TablePropertiesCollection {
            raw: raw
        }
    }
}

impl Drop for TablePropertiesCollection {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_table_props_collection_destroy(self.raw);
        }
    }
}

impl TablePropertiesCollection {
    pub fn len(&self) -> usize {
        unsafe {
            ll::rocks_table_props_collection_size(self.raw) as usize
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn iter<'a>(&'a self) -> TablePropertiesCollectionIter<'a> {
        TablePropertiesCollectionIter {
            raw: unsafe { ll::rocks_table_props_collection_iter_create(self.raw) },
            size: self.len(),
            at_end: self.is_empty(),
            _marker: PhantomData,
        }
    }
}

pub struct TablePropertiesCollectionIter<'a> {
    raw: *mut ll::rocks_table_props_collection_iter_t,
    size: usize,
    at_end: bool,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for TablePropertiesCollectionIter<'a> {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_table_props_collection_iter_destroy(self.raw);
        }
    }
}

impl<'a> Iterator for TablePropertiesCollectionIter<'a> {
    type Item = (String, TableProperties<'a>);

    fn next(&mut self) -> Option<(String, TableProperties<'a>)> {
        if self.raw.is_null() || self.at_end {
            None
        } else {
            let mut key = String::new();
            unsafe {
                ll::rocks_table_props_collection_iter_key(self.raw,
                                                          &mut key as *mut String as *mut c_void);
                let prop = TableProperties::from_ll(ll::rocks_table_props_collection_iter_value(self.raw));
                self.at_end = ll::rocks_table_props_collection_iter_next(self.raw) == 0;
                // FIXME: can't use &str here, since each time iterator->first will be reused
                Some((key, prop))
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

/// Other than basic table properties, each table may also have the user
/// collected properties.
///
/// The value of the user-collected properties are encoded as raw bytes --
/// users have to interprete these values by themselves.
///
/// Rust: wraps, and exposes a `{String => Vec<u8>}` map
#[repr(C)]
#[derive(Debug)]
pub struct UserCollectedProperties {
    // *std::map<std::string, std::string>
    raw: *mut c_void,
}

impl ToRaw<ll::rocks_user_collected_props_t> for UserCollectedProperties {
    fn raw(&self) -> *mut ll::rocks_user_collected_props_t {
        unsafe {
            mem::transmute(self as *const UserCollectedProperties as *mut c_void)
        }
    }
}

impl UserCollectedProperties {
    pub fn insert(&mut self, k: &str, v: &[u8]) {
        unimplemented!()
    }

    pub fn len(&self) -> usize {
        unsafe {
            ll::rocks_user_collected_props_size(self.raw()) as usize
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn iter<'a>(&'a self) -> UserCollectedPropertiesIter<'a> {
        UserCollectedPropertiesIter {
            raw: unsafe { ll::rocks_user_collected_props_iter_create(self.raw()) },
            size: self.len(),
            at_end: self.is_empty(),
            _marker: PhantomData,
        }
    }
}

pub struct UserCollectedPropertiesIter<'a> {
    raw: *mut ll::rocks_user_collected_props_iter_t,
    size: usize,
    at_end: bool,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for UserCollectedPropertiesIter<'a> {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_user_collected_props_iter_destroy(self.raw);
        }
    }
}

impl<'a> Iterator for UserCollectedPropertiesIter<'a> {
    // FIXME: is {String => Vec<u8>} right?
    type Item = (String, Vec<u8>);

    fn next(&mut self) -> Option<(String, Vec<u8>)> {
        if self.raw.is_null() || self.at_end {
            None
        } else {
            let mut key = String::new();
            let mut value = Vec::new();
            unsafe {
                ll::rocks_user_collected_props_iter_key(self.raw,
                                                        &mut key as *mut String as *mut c_void);
                ll::rocks_user_collected_props_iter_value(self.raw,
                                                        &mut value as *mut Vec<u8> as *mut c_void);
                self.at_end = ll::rocks_user_collected_props_iter_next(self.raw) == 0;
            }
            Some((key, value))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum EntryType {
    EntryPut,
    EntryDelete,
    EntrySingleDelete,
    EntryMerge,
    EntryOther,
}

/// `TablePropertiesCollector` provides the mechanism for users to collect
/// their own properties that they are interested in. This class is essentially
/// a collection of callback functions that will be invoked during table
/// building. It is construced with TablePropertiesCollectorFactory. The methods
/// don't need to be thread-safe, as we will create exactly one
/// TablePropertiesCollector object per table and then call it sequentially
pub trait TablePropertiesCollector {
    /// AddUserKey() will be called when a new key/value pair is inserted into the
    /// table.
    ///
    /// @params key    the user key that is inserted into the table.
    /// @params value  the value that is inserted into the table.
    fn add_user_key(&mut self, key: &[u8],  value: &[u8],
                    type_: EntryType, seq: SequenceNumber,
                    file_size: u64);

    /// Finish() will be called when a table has already been built and is ready
    /// for writing the properties block.
    /// @params properties  User will add their collected statistics to
    /// `properties`.
    fn finish(&mut self, properties: &mut UserCollectedProperties);

    /// The name of the properties collector can be used for debugging purpose.
    fn name(&self) -> &str {
        "RustTablePropertiesCollector\0"
    }

    // fn need_compact(&self) -> bool
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Context {
    column_family_id: u32,
}

// Constructs TablePropertiesCollector. Internals create a new
// TablePropertiesCollector for each new table
pub trait TablePropertiesCollectorFactory {
    fn create_table_properties_collector(&mut self, context: Context) -> Box<TablePropertiesCollector>;

    fn name(&self) -> &str {
        "RustTablePropertiesCollectorFactory\0"
    }
}

/// TableProperties contains a bunch of read-only properties of its associated
/// table.
#[repr(C)]
pub struct TableProperties<'a> {
    raw: *mut ll::rocks_table_props_t,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for TableProperties<'a> {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_table_props_destroy(self.raw);
        }
    }
}

impl<'a> FromRaw<ll::rocks_table_props_t> for TableProperties<'a> {
    unsafe fn from_ll(raw: *mut ll::rocks_table_props_t) -> Self {
        TableProperties {
            raw: raw,
            _marker: PhantomData,
        }
    }
}

impl<'a> fmt::Display for TableProperties<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut ret = String::new();
        unsafe {
            ll::rocks_table_props_to_string(self.raw, &mut ret as *mut String as *mut c_void);
        }
        write!(f, "{}", ret)
    }
}

impl<'a> fmt::Debug for TableProperties<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TableProperties({:?})", self.to_string())
    }
}

impl<'a> TableProperties<'a> {
    // the total size of all data blocks.
    pub fn data_size(&self) -> u64 {
        unsafe {
            ll::rocks_table_props_get_data_size(self.raw)
        }
    }
    // the size of index block.
    pub fn index_size(&self) -> u64 {
        0
    }
    // the size of filter block.
    pub fn filter_size(&self) -> u64 {
        0
    }
    // total raw key size
    pub fn raw_key_size(&self) -> u64 {
        0
    }
    // total raw value size
    pub fn raw_value_size(&self) -> u64 {
        0
    }
    // the number of blocks in this table
    pub fn num_data_blocks(&self) -> u64 {
        0
    }
    // the number of entries in this table
    pub fn num_entries(&self) -> u64 {
        0
    }
    // format version, reserved for backward compatibility
    pub fn format_version(&self) -> u64 {
        0
    }
    // If 0, key is variable length. Otherwise number of bytes for each key.
    pub fn fixed_key_len(&self) -> u64 {
        0
    }
    // ID of column family for this SST file, corresponding to the CF identified
    // by column_family_name.
    pub fn column_family_id(&self) -> u64 {
        0
    }

    // Name of the column family with which this SST file is associated.
    // If column family is unknown, `column_family_name` will be an empty string.
    pub fn column_family_name(&self) -> Option<&str> {
        None
    }

    // The name of the filter policy used in this table.
    // If no filter policy is used, `filter_policy_name` will be an empty string.
    pub fn filter_policy_name(&self) -> Option<&str> {
        None
    }

    // The name of the comparator used in this table.
    pub fn comparator_name(&self) -> &str {
        ""
    }

    // The name of the merge operator used in this table.
    // If no merge operator is used, `merge_operator_name` will be "nullptr".
    pub fn merge_operator_name(&self) -> Option<&str> {
        None
    }

    // The name of the prefix extractor used in this table
    // If no prefix extractor is used, `prefix_extractor_name` will be "nullptr".
    pub fn prefix_extractor_name(&self) -> Option<&str> {
        None
    }

    // The names of the property collectors factories used in this table
    // separated by commas
    // {collector_name[1]},{collector_name[2]},{collector_name[3]} ..
    pub fn property_collectors_names(&self) -> &str {
        ""
    }

    // The compression algo used to compress the SST files.
    pub fn compression_name(&self) -> &str {
        ""
    }

    // user collected properties
    pub fn user_collected_properties(&self) -> &UserCollectedProperties {
        unsafe {
            let raw_ptr = ll::rocks_table_props_get_user_collected_properties(self.raw);
            mem::transmute(raw_ptr)
        }
    }

    pub fn readable_properties(&self) -> &UserCollectedProperties {
        unsafe {
            let raw_ptr = ll::rocks_table_props_get_readable_properties(self.raw);
            mem::transmute(raw_ptr)
        }
    }
}

<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;

/*
#[macro_use]
extern crate serde_derive;
*/

use std::collections::HashMap;

use serde_json::Value;

#[derive(Serialize, Deserialize, Debug)]
//allow(dead_code)]
pub struct Init {
    pub access_token: String,
    pub home_server: String,
    pub user_id: String,
    pub device_id: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct MatrixSync {
    /*
    account_data: Events,
    device_lists: HashMap,
    */
    pub next_batch: String,
    //presence: HashMap,
    pub rooms: Rooms,
    //to_device: HashMap,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct Rooms {
    pub invite: HashMap<String, Room>,
    pub join: HashMap<String, Room>,
    pub leave: HashMap<String, Room>,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct Room {
    pub account_data: Value,
    pub ephemeral: Value,
    pub state: Events,
    pub timeline: Events,
    pub unread_notifications: Value
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct Events {
    pub events: Vec<Event>,
    pub limited: Option<bool>,
    pub prev_batch: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[allow(dead_code)]
pub struct Event {
    pub content: Value,
    pub event_id: String,
    //membership: String,
    pub origin_server_ts: u64,
    pub sender: String,
    //state_key: String,
    #[serde(rename="type")]
    pub type_: String,
    pub unsigned: Value
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct PublicRooms {
    pub total_room_count_estimate: u32,
    pub next_batch: String,
    pub chunk: Vec<PublicRoom>,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct PublicRoom {
    pub canonical_alias: Option<String>,
    pub name: String,
    pub world_readable: bool,
    pub topic: Option<String>,
    pub num_joined_members: u32,
    pub avatar_url: Option<String>,
    pub room_id: String,
    pub guest_can_join: bool,
    pub aliases: Option<Vec<String>>,
}
<commit_msg>Update MatrixTypes to fix serialization errors<commit_after>extern crate serde;
extern crate serde_json;

/*
#[macro_use]
extern crate serde_derive;
*/

use std::collections::HashMap;

use serde_json::Value;

#[derive(Serialize, Deserialize, Debug)]
//allow(dead_code)]
pub struct Init {
    pub access_token: String,
    pub home_server: String,
    pub user_id: String,
    pub device_id: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct MatrixSync {
    /*
    account_data: Events,
    device_lists: HashMap,
    */
    pub next_batch: String,
    //presence: HashMap,
    pub rooms: Rooms,
    //to_device: HashMap,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct Rooms {
    pub invite: HashMap<String, InviteRoom>,
    pub join: HashMap<String, Room>,
    //pub leave: HashMap<String, Room>,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct Room {
    pub account_data: Value,
    pub ephemeral: Value,
    pub state: Events,
    pub timeline: Events,
    pub unread_notifications: Value
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct InviteRoom {
    invite_state: InviteEvents,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct InviteEvents {
    events: Vec<Event>,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct Events {
    pub events: Vec<Event>,
    pub limited: Option<bool>,
    pub prev_batch: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[allow(dead_code)]
pub struct Event {
    pub content: Value,
    pub event_id: Option<String>,
    //membership: String,
    pub origin_server_ts: Option<u64>,
    pub sender: String,
    //state_key: String,
    #[serde(rename="type")]
    pub type_: String,
    pub unsigned: Option<Value>
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct PublicRooms {
    pub total_room_count_estimate: u32,
    pub next_batch: String,
    pub chunk: Vec<PublicRoom>,
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(dead_code)]
pub struct PublicRoom {
    pub canonical_alias: Option<String>,
    pub name: String,
    pub world_readable: bool,
    pub topic: Option<String>,
    pub num_joined_members: u32,
    pub avatar_url: Option<String>,
    pub room_id: String,
    pub guest_can_join: bool,
    pub aliases: Option<Vec<String>>,
}
<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `librustc`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `librustc_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `librustc`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use crate::common::parse;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path).parse().unwrap();
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_span::with_session_globals(edition, || {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &librustc_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
            }
        }
    });

    (passed, failed)
}

fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::librustc_expr(input).and_then(librustc_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on librustc objects.
fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Block, BorrowKind, Expr, ExprKind, Field, GenericArg, MacCall, Pat, Stmt, StmtKind, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;

    struct BracketsVisitor {
        failed: bool,
    };

    fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(path, fields, expr) => {
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                visit_opt(expr, |expr| vis.visit_expr(expr));
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            noop_visit_expr(e, self);
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                            tokens: None,
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArg::Const(arg) => noop_visit_expr(&mut arg.value, self),
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn visit_mac(&mut self, mac: &mut MacCall) {
            // By default when folding over macros, librustc panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement visit_mac to just return the macro
            // unchanged.
            let _ = mac;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut librustc_expr);
    if folder.failed {
        None
    } else {
        Some(librustc_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArgument::Const(a) => GenericArgument::Const(fold_expr(self, a)),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_generic_method_argument(
            &mut self,
            arg: GenericMethodArgument,
        ) -> GenericMethodArgument {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericMethodArgument::Const(a) => GenericMethodArgument::Const(fold_expr(self, a)),
                _ => fold_generic_method_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(tokens) if tokens.is_empty() => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>Update test suite to nightly-2020-11-11<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `librustc`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `librustc_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `librustc`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use crate::common::parse;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path).parse().unwrap();
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_span::with_session_globals(edition, || {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &librustc_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
            }
        }
    });

    (passed, failed)
}

fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::librustc_expr(input).and_then(librustc_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on librustc objects.
fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Block, BorrowKind, Expr, ExprKind, Field, GenericArg, Pat, Stmt, StmtKind, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;

    struct BracketsVisitor {
        failed: bool,
    };

    fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(path, fields, expr) => {
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                visit_opt(expr, |expr| vis.visit_expr(expr));
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            noop_visit_expr(e, self);
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                            tokens: None,
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArg::Const(arg) => noop_visit_expr(&mut arg.value, self),
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut librustc_expr);
    if folder.failed {
        None
    } else {
        Some(librustc_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArgument::Const(a) => GenericArgument::Const(fold_expr(self, a)),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_generic_method_argument(
            &mut self,
            arg: GenericMethodArgument,
        ) -> GenericMethodArgument {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericMethodArgument::Const(a) => GenericMethodArgument::Const(fold_expr(self, a)),
                _ => fold_generic_method_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(tokens) if tokens.is_empty() => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::eq::SpanlessEq;
use common::parse;

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path
                .to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path);
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_ast::with_globals(edition, || {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
            }
        }
    });

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Block, BorrowKind, Expr, ExprKind, Field, GenericArg, MacCall, Pat, Stmt, StmtKind, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;

    struct BracketsVisitor {
        failed: bool,
    };

    fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(path, fields, expr) => {
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                visit_opt(expr, |expr| vis.visit_expr(expr));
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            noop_visit_expr(e, self);
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArg::Const(arg) => noop_visit_expr(&mut arg.value, self),
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn visit_mac(&mut self, mac: &mut MacCall) {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement visit_mac to just return the macro
            // unchanged.
            let _ = mac;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(libsyntax_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArgument::Const(a) => GenericArgument::Const(fold_expr(self, a)),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(tokens) if tokens.is_empty() => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>Remove unnecessarily suppressed test<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::eq::SpanlessEq;
use common::parse;

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path);
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_ast::with_globals(edition, || {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
            }
        }
    });

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Block, BorrowKind, Expr, ExprKind, Field, GenericArg, MacCall, Pat, Stmt, StmtKind, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;

    struct BracketsVisitor {
        failed: bool,
    };

    fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(path, fields, expr) => {
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                visit_opt(expr, |expr| vis.visit_expr(expr));
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            noop_visit_expr(e, self);
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArg::Const(arg) => noop_visit_expr(&mut arg.value, self),
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn visit_mac(&mut self, mac: &mut MacCall) {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement visit_mac to just return the macro
            // unchanged.
            let _ = mac;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(libsyntax_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                // Don't wrap const generic arg as that's invalid syntax.
                GenericArgument::Const(a) => GenericArgument::Const(fold_expr(self, a)),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(tokens) if tokens.is_empty() => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, BufReader, BufRead};
use std::path::Path;
use std::collections::HashMap;

#[derive(Debug, PartialEq)]
enum ConfigType {
    String,
    Boolean,
    Vector,
}

#[derive(Debug)]
struct ConfigVariable {
    var_type: ConfigType,
    value: String,
}

impl ConfigVariable {
    fn extract_value_as_string(&self, typ: ConfigType) -> Result<String, String> {
        if self.var_type == typ {
            Ok(self.value.to_owned())
        } else {
            Err(format!("Incorrect variable type. Expected: {:?}. Actual: {:?}",
                        typ,
                        self.var_type))
        }
    }
}

trait FromConfig {
    fn from_config(param: &ConfigParams, key: &str) -> Result<Self, String>
        where Self: std::marker::Sized;
}

impl FromConfig for String {
    fn from_config(param: &ConfigParams, key: &str) -> Result<String, String> {
        match param.params.get(key) {
            Some(variable) => variable.extract_value_as_string(ConfigType::String),
            None => Err(format!("Unknown configuration parameter: {:?}", key)),
        }
    }
}

impl FromConfig for bool {
    fn from_config(param: &ConfigParams, key: &str) -> Result<bool, String> {
        match param.params.get(key) {
            Some(variable) => {
                variable.extract_value_as_string(ConfigType::Boolean)
                    .map(|x| x.parse::<bool>().unwrap())
            }
            None => Ok(false),
        }

    }
}

impl FromConfig for Vec<String> {
    fn from_config(param: &ConfigParams, key: &str) -> Result<Vec<String>, String> {
        match param.params.get(key) {
            Some(variable) => {
                variable.extract_value_as_string(ConfigType::Vector)
                    .map(|string| string.split(",").map(|item| item.trim().to_owned()).collect())
            }
            None => Err(format!("Unknown configuration parameter: {:?}", key)),
        }

    }
}

#[derive(Debug)]
struct ConfigParams {
    params: HashMap<String, ConfigVariable>,
}

impl ConfigParams {
    fn new() -> ConfigParams {
        ConfigParams { params: HashMap::new() }
    }

    fn parse<P: AsRef<Path>>(path: P) -> ConfigParams {
        let conf_file = File::open(path).unwrap();
        let content = BufReader::new(conf_file);

        let is_not_comment = |x: &Result<String, io::Error>| {
            match x {
                &Err(_) => false,
                &Ok(ref line) => {
                    !(line.starts_with("#") || line.starts_with(";") || line.is_empty())
                }
            }
        };
        let mut params = ConfigParams::new();
        for line in content.lines().filter(is_not_comment) {
            if line.is_ok() {
                params.update_config(line.unwrap());
            }
        }

        params
    }
    // Will parse the line and update the internal structure
    fn update_config(&mut self, line: String) {
        let mut parts = line.splitn(2, " ").map(|x| x.to_owned());
        let key = parts.next().unwrap().to_lowercase();
        match parts.next() {
            None => {
                self.params.insert(key,
                                   ConfigVariable {
                                       var_type: ConfigType::Boolean,
                                       value: "true".to_owned(),
                                   });
            }
            Some(value) => {
                if value.contains(",") {
                    self.params.insert(key,
                                       ConfigVariable {
                                           var_type: ConfigType::Vector,
                                           value: value,
                                       });
                } else {
                    self.params.insert(key,
                                       ConfigVariable {
                                           var_type: ConfigType::String,
                                           value: value,
                                       });
                }
            }
        }

    }

    fn param<T: FromConfig>(&self, key: &str) -> Result<T, String> {
        key.to_lowercase();
        FromConfig::from_config(&self, key)
    }
}

fn main() {
    const CONF: &'static str = "test.conf";
    let params = ConfigParams::parse(CONF);

    println!("{:?}", params.param::<String>("fullname"));
    println!("{:?}", params.param::<String>("favouritefruit"));
    println!("{:?}", params.param::<bool>("needspeeling"));
    println!("{:?}", params.param::<bool>("seedsremoved"));
    println!("{:?}", params.param::<Vec<String>>("otherfamily"));
}

#[cfg(test)]
mod tests {

    #[test]
    fn main_test() {
        const CONF: &'static str = "test.conf";
        let params = super::ConfigParams::parse(CONF);
        assert_eq!(params.param::<String>("fullname").unwrap(), "Foo Barber");
        assert_eq!(params.param::<String>("favouritefruit").unwrap(), "banana");
        assert!(params.param::<bool>("needspeeling").unwrap());
        assert!(!params.param::<bool>("seedsremoved").unwrap());
        assert_eq!(params.param::<Vec<String>>("otherfamily").unwrap(),
                   vec!["Rhu Barber", "Harry Barber"]);
    }
}
<commit_msg>Changed to use enum rather than string.<commit_after>use std::fs::File;
use std::io::{self, BufReader, BufRead};
use std::path::Path;
use std::collections::HashMap;

#[derive(Debug)]
enum ConfigVariable {
    String(String),
    Boolean(bool),
    Vector(Vec<String>),
}

trait FromConfig: Sized {
    fn from_config(param: &ConfigParams, key: &str) -> Result<Self, String>;
}

impl FromConfig for String {
    fn from_config(param: &ConfigParams, key: &str) -> Result<String, String> {
        match param.params.get(key) {
            Some(&ConfigVariable::String(ref value)) => Ok(value.clone()),
            _ => Err(format!("Unknown configuration parameter: {:?}", key)),
        }
    }
}

impl FromConfig for bool {
    fn from_config(param: &ConfigParams, key: &str) -> Result<bool, String> {
        match param.params.get(key) {
            Some(&ConfigVariable::Boolean(value)) => Ok(value),
            _ => Ok(false),
        }

    }
}

impl FromConfig for Vec<String> {
    fn from_config(param: &ConfigParams, key: &str) -> Result<Vec<String>, String> {
        match param.params.get(key) {
            Some(&ConfigVariable::Vector(ref value)) => Ok(value.clone()),
            _ => Err(format!("Unknown configuration parameter: {:?}", key)),
        }

    }
}

#[derive(Debug)]
struct ConfigParams {
    params: HashMap<String, ConfigVariable>,
}

impl ConfigParams {
    fn new() -> ConfigParams {
        ConfigParams { params: HashMap::new() }
    }

    fn parse<P: AsRef<Path>>(path: P) -> ConfigParams {
        let conf_file = File::open(path).unwrap();
        let content = BufReader::new(conf_file);

        let is_not_comment = |x: &Result<String, io::Error>| {
            match x {
                &Err(_) => false,
                &Ok(ref line) => {
                    !(line.starts_with("#") || line.starts_with(";") || line.is_empty())
                }
            }
        };
        let mut params = ConfigParams::new();
        for line in content.lines().filter(is_not_comment) {
            if line.is_ok() {
                params.update_config(line.unwrap());
            }
        }

        params
    }
    // Will parse the line and update the internal structure
    fn update_config(&mut self, line: String) {
        let mut parts = line.splitn(2, " ").map(|x| x.to_owned());
        let key = parts.next().unwrap().to_lowercase();
        match parts.next() {
            None => {
                self.params.insert(key, ConfigVariable::Boolean(true));
            }
            Some(value) => {
                if value.contains(",") {
                    self.params.insert(key,
                                       ConfigVariable::Vector(value.split(",")
                                           .map(|item| item.trim().to_owned())
                                           .collect()));
                } else {
                    self.params.insert(key, ConfigVariable::String(value));
                }
            }
        }

    }

    fn param<T: FromConfig>(&self, key: &str) -> Result<T, String> {
        key.to_lowercase();
        FromConfig::from_config(&self, key)
    }
}

fn main() {
    const CONF: &'static str = "test.conf";
    let params = ConfigParams::parse(CONF);

    println!("{:?}", params.param::<String>("fullname"));
    println!("{:?}", params.param::<String>("favouritefruit"));
    println!("{:?}", params.param::<bool>("needspeeling"));
    println!("{:?}", params.param::<bool>("seedsremoved"));
    println!("{:?}", params.param::<Vec<String>>("otherfamily"));
}

#[cfg(test)]
mod tests {

    #[test]
    fn main_test() {
        const CONF: &'static str = "test.conf";
        let params = super::ConfigParams::parse(CONF);
        assert_eq!(params.param::<String>("fullname").unwrap(), "Foo Barber");
        assert_eq!(params.param::<String>("favouritefruit").unwrap(), "banana");
        assert!(params.param::<bool>("needspeeling").unwrap());
        assert!(!params.param::<bool>("seedsremoved").unwrap());
        assert_eq!(params.param::<Vec<String>>("otherfamily").unwrap(),
                   vec!["Rhu Barber", "Harry Barber"]);
    }
}
<|endoftext|>


<commit_before><commit_msg>fix: use default instead of new<commit_after><|endoftext|>


<commit_before><commit_msg>Fix panic when uploading a GPU buffer of size 0.<commit_after><|endoftext|>