<commit_before>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available only 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 crate::Lifetime;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::marker::PhantomData;
use std::ptr;
use std::slice;

/// 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 only if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not implement clone on this - there are raw pointers inside
    // these entries which will be messed up. Moving the `TokenBuffer` itself is
    // safe as the data pointed to won't be moved.
    ptr: *const Entry,
    len: usize,
}

impl Drop for TokenBuffer {
    fn drop(&mut self) {
        unsafe {
            let slice = slice::from_raw_parts_mut(self.ptr as *mut Entry, self.len);
            let _ = Box::from_raw(slice);
        }
    }
}

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 groups = 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 temporarily.
                    groups.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 groups {
            // 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 group_up = unsafe { entries.as_ptr().add(idx + 1) };

            // 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(), group_up);
            entries[idx] = Entry::Group(group, inner);
        }

        let len = entries.len();
        let ptr = Box::into_raw(entries);
        TokenBuffer {
            ptr: ptr as *const Entry,
            len,
        }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `TokenStream`.
    ///
    /// *This method is available only 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.ptr, self.ptr.add(self.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 only if Syn is built with the `"parsing"` feature.*
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)
    }

    /// While 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) {
        while 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.ptr, self.scope);
                }
            } else {
                break;
            }
        }
    }

    /// 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() }),
        }
    }
}

impl<'a> Copy for Cursor<'a> {}

impl<'a> Clone for Cursor<'a> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a> Eq for Cursor<'a> {}

impl<'a> PartialEq for Cursor<'a> {
    fn eq(&self, other: &Self) -> bool {
        let Cursor { ptr, scope, marker } = self;
        let _ = marker;
        *ptr == other.ptr && *scope == other.scope
    }
}

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>Clarify new vs new2 in TokenBuffer documentation<commit_after>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available only 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 crate::Lifetime;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::marker::PhantomData;
use std::ptr;
use std::slice;

/// 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 only if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not implement clone on this - there are raw pointers inside
    // these entries which will be messed up. Moving the `TokenBuffer` itself is
    // safe as the data pointed to won't be moved.
    ptr: *const Entry,
    len: usize,
}

impl Drop for TokenBuffer {
    fn drop(&mut self) {
        unsafe {
            let slice = slice::from_raw_parts_mut(self.ptr as *mut Entry, self.len);
            let _ = Box::from_raw(slice);
        }
    }
}

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 groups = 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 temporarily.
                    groups.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 groups {
            // 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 group_up = unsafe { entries.as_ptr().add(idx + 1) };

            // 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(), group_up);
            entries[idx] = Entry::Group(group, inner);
        }

        let len = entries.len();
        let ptr = Box::into_raw(entries);
        TokenBuffer {
            ptr: ptr as *const Entry,
            len,
        }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `proc_macro::TokenStream`.
    ///
    /// *This method is available only 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
    /// `proc_macro2::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.ptr, self.ptr.add(self.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 only if Syn is built with the `"parsing"` feature.*
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)
    }

    /// While 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) {
        while 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.ptr, self.scope);
                }
            } else {
                break;
            }
        }
    }

    /// 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() }),
        }
    }
}

impl<'a> Copy for Cursor<'a> {}

impl<'a> Clone for Cursor<'a> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a> Eq for Cursor<'a> {}

impl<'a> PartialEq for Cursor<'a> {
    fn eq(&self, other: &Self) -> bool {
        let Cursor { ptr, scope, marker } = self;
        let _ = marker;
        *ptr == other.ptr && *scope == other.scope
    }
}

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>use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::thread;

use chatmap::{ChatMap, ClientInfo};
use command::{Command, parse_command};
use message::Message;

extern crate time;

pub fn create_client(stream: TcpStream,
                     sender_to_router: Sender<Message>,
                     chat_map: &Arc<Mutex<ChatMap>>) {

    println!("New client");
    let mut stream = stream;

    stream.write(&"Welcome to Smazy\n".to_string().into_bytes()).unwrap();
    stream.write(&"Please enter a username:\n".to_string().into_bytes()).unwrap();
    stream.flush().unwrap();

    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut username = "".to_string();

    match reader.read_line(&mut username) {
        Ok(n) => {
            let username = username.trim().to_string();
            let (sender_to_client, receiver_from_router) = channel();

            {
                let mut guard = chat_map.lock().unwrap();
                if n > 0 && !guard.contains_key(&username) {
                    let client_info = ClientInfo{
                        partner: None,
                        sender_to_client: sender_to_client
                    };
                    guard.insert(username.to_string(), client_info);
                    println!("New user: {}", username.to_string());
                }
            }

            let partner = choose_chat_partner(stream.try_clone().unwrap(),
                username.to_string(), chat_map);

            chat(stream, username, partner, sender_to_router, receiver_from_router, chat_map);
        },

        Err(e) => println!("{}", e)
    }
}

fn display_available(stream: TcpStream, chat_map: &Arc<Mutex<ChatMap>>, username: String) {
    let mut stream = stream;

    let show_available_msg = "Here are the users available to chat:\n".to_string();
    stream.write(&show_available_msg.into_bytes()).unwrap();

    {
        let guard = chat_map.lock().unwrap();
        for (name, client_info) in guard.iter() {
            if &name[..] != &username[..] && client_info.partner == None {
                stream.write(&name.to_string().into_bytes()).unwrap();
                stream.write(&"\n".to_string().into_bytes()).unwrap();
            }
        }
    }
}

fn choose_chat_partner(stream: TcpStream,
                       username: String,
                       chat_map: &Arc<Mutex<ChatMap>>) -> String {

    display_available(stream.try_clone().unwrap(), &chat_map, username.to_string());

    let mut stream = stream;

    let select_msg = "Select who you want to chat with:\n".to_string();
    stream.write(&select_msg.into_bytes()).unwrap();

    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut partner = "".to_string();

    match reader.read_line(&mut partner) {
        Ok(_) => {
            partner = partner.trim().to_string();

            if !try_select_partner(chat_map, username.to_string(), partner.to_string()) {
                return choose_chat_partner(stream, username, chat_map);
            }
        }
        Err(e) => println!("{}", e)
    }

    partner
}

fn try_select_partner(chat_map: &Arc<Mutex<ChatMap>>,
                      username: String,
                      partner: String) -> bool {

    let success: bool;
    {
        let mut guard = chat_map.lock().unwrap();

        match guard.get_mut(&partner) {
            Some(clientinfo) => {
                if &partner[..] != &username[..]
                    && (clientinfo.partner == None
                        || clientinfo.partner == Some(username.to_string())) {
                    clientinfo.partner = Some(username.to_string());
                    success = true;
                } else {
                    success = false;
                }
            },
            None => success = false
        }
    }

    if success {
        let mut guard = chat_map.lock().unwrap();
        println!("Assigning partner {} to {}", partner, username);
        guard.get_mut(&username).unwrap().partner = Some(partner.to_string());
    }
    success
}

fn chat(stream: TcpStream,
        username: String,
        partner: String,
        sender_to_router: Sender<Message>,
        receiver_from_router: Receiver<Message>,
        chat_map: &Arc<Mutex<ChatMap>>) {

    let mut partner = partner.to_string();

    // Send messages
    {
        let username = username.clone();
        let chat_map = chat_map.clone();
        let stream = stream.try_clone().unwrap();
        let reader = BufReader::new(stream.try_clone().unwrap());
        thread::spawn(move|| {
            let mut lines = reader.lines();
            while let Some(Ok(line)) = lines.next() {
                println!("{}",line);

                let msg = Message::new(time::now().asctime().to_string(),
                                       username.to_string(),
                                       partner.to_string(),
                                       line.to_string());

                if &line[0..1] == "/" {
                    match parse_command(msg.content().to_string()) {
                        Command::Quit => {
                            println!("Quit command");
                            quit_conversation(&chat_map, username.to_string(), partner.to_string());
                            partner = choose_chat_partner(stream.try_clone().unwrap(), username.to_string(), &chat_map);
                        },
                        Command::DisplayAvailable => {
                            display_available(stream.try_clone().unwrap(), &chat_map, username.to_string());
                        },
                        Command::Logoff => println!("Logoff command"),
                        Command::Unrecognized => println!("Unrecognized command")
                    }
                } else {
                    sender_to_router.send(msg).unwrap();
                }
            }
        });
    }

    // Receive Messages
    {
        let username = username.clone();
        thread::spawn(move|| {
            loop {
                let stream = stream.try_clone().unwrap();
                match receiver_from_router.try_recv() {
                    Ok(msg) => {
                        println!("User {} received message: {}",
                            &username, msg.content());

                        receive_message(stream, msg);
                    },

                    Err(TryRecvError::Empty) => continue,

                    Err(TryRecvError::Disconnected) =>
                        panic!("User {} disconnected from router", &username)
                }
            }
        });
    }
}

fn receive_message(stream: TcpStream, msg: Message) {
    let mut stream = stream;
    let output = msg.from().to_string() + ": " + &msg.content()[..] + "\n";
    stream.write(&output.into_bytes()).unwrap();
}

fn quit_conversation(chat_map: &Arc<Mutex<ChatMap>>, username: String, partner: String) {
    let mut guard = chat_map.lock().unwrap();
    guard.get_mut(&username).unwrap().partner = None;
    guard.get_mut(&partner).unwrap().partner = None;
}

#[cfg(test)]
mod client_tests {

    use std::sync::{Arc, Mutex};
    use std::sync::mpsc::channel;
    use chatmap::{ChatMap, ClientInfo};
    use super::try_select_partner;

    #[test]
    fn try_select_partner_test_success_1() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));
    }

    #[test]
    fn try_select_partner_test_success_2() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Success: c and d become partners
        assert!(try_select_partner(&cm, "c".to_string(), "d".to_string()));
    }

    #[test]
    fn try_select_partner_test_succes_3() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Success: b can choose a when they are already partners
        //   (This allows someone to confirm a chat request)
        assert!(try_select_partner(&cm, "b".to_string(), "a".to_string()));
    }

    #[test]
    fn try_select_partner_test_fail_1() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Fail: b already has a partner
        assert!(!try_select_partner(&cm, "c".to_string(), "b".to_string()));
    }

    #[test]
    fn try_select_partner_test_fail_2() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Fail: Can't choose self as partner
        assert!(!try_select_partner(&cm, "c".to_string(), "c".to_string()));
    }

    #[test]
    fn try_select_partner_test_fail_3() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Success: c and d become partners
        assert!(try_select_partner(&cm, "c".to_string(), "d".to_string()));

        // Fail: c already has a partner
        assert!(!try_select_partner(&cm, "e".to_string(), "c".to_string()));

        // Fail: d already has a partner
        assert!(!try_select_partner(&cm, "e".to_string(), "d".to_string()));
    }

    fn fixture() -> ChatMap {
        let mut cm = ChatMap::new();
        let (sender_to_a, _) = channel();
        cm.insert("a".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_a
        });
        let (sender_to_b, _) = channel();
        cm.insert("b".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_b
        });
        let (sender_to_c, _) = channel();
        cm.insert("c".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_c
        });
        let (sender_to_d, _) = channel();
        cm.insert("d".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_d
        });
        let (sender_to_e, _) = channel();
        cm.insert("e".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_e
        });
        cm
    }
}<commit_msg>Checks username to prevent repeat names and names that begin with command character ("/")<commit_after>use std::io::{BufRead, BufReader, Write};
use std::net::TcpStream;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::thread;

use chatmap::{ChatMap, ClientInfo};
use command::{Command, parse_command};
use message::Message;

extern crate time;

pub fn create_client(stream: TcpStream,
                     sender_to_router: Sender<Message>,
                     chat_map: &Arc<Mutex<ChatMap>>) {

    println!("New client");
    let mut stream = stream;

    stream.write(&"Welcome to Smazy\n".to_string().into_bytes()).unwrap();
    stream.write(&"Please enter a username:\n".to_string().into_bytes()).unwrap();
    stream.flush().unwrap();

    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut username = "".to_string();
    let (sender_to_client, receiver_from_router) = channel();

    loop {
        match reader.read_line(&mut username) {
            Ok(_) => {
                username = username.trim().to_string();

                {
                    let mut guard = chat_map.lock().unwrap();
                    if username.len() > 0  && !guard.contains_key(&username) && &username[0..1] != "/" {

                        let client_info = ClientInfo{
                            partner: None,
                            sender_to_client: sender_to_client
                        };
                        guard.insert(username.to_string(), client_info);

                        println!("New user: {}", username.to_string());
                        break;
                    }
                    else {
                        stream.write(&"Invalid username. Please try again.\n".to_string().into_bytes()).unwrap();
                        username = "".to_string();
                    }
                }
            },
            Err(e) => println!("{}", e)
        }
    }

    let partner = choose_chat_partner(stream.try_clone().unwrap(),
        username.to_string(), chat_map);

    chat(stream, username, partner, sender_to_router, receiver_from_router, chat_map);
}

fn display_available(stream: TcpStream, chat_map: &Arc<Mutex<ChatMap>>, username: String) {
    let mut stream = stream;

    let show_available_msg = "Here are the users available to chat:\n".to_string();
    stream.write(&show_available_msg.into_bytes()).unwrap();

    {
        let guard = chat_map.lock().unwrap();
        for (name, client_info) in guard.iter() {
            if &name[..] != &username[..] && client_info.partner == None {
                stream.write(&name.to_string().into_bytes()).unwrap();
                stream.write(&"\n".to_string().into_bytes()).unwrap();
            }
        }
    }
}

fn choose_chat_partner(stream: TcpStream,
                       username: String,
                       chat_map: &Arc<Mutex<ChatMap>>) -> String {

    display_available(stream.try_clone().unwrap(), &chat_map, username.to_string());

    let mut stream = stream;

    let select_msg = "Select who you want to chat with:\n".to_string();
    stream.write(&select_msg.into_bytes()).unwrap();

    let mut reader = BufReader::new(stream.try_clone().unwrap());
    let mut partner = "".to_string();

    match reader.read_line(&mut partner) {
        Ok(_) => {
            partner = partner.trim().to_string();

            if !try_select_partner(chat_map, username.to_string(), partner.to_string()) {
                return choose_chat_partner(stream, username, chat_map);
            }
        }
        Err(e) => println!("{}", e)
    }

    partner
}

fn try_select_partner(chat_map: &Arc<Mutex<ChatMap>>,
                      username: String,
                      partner: String) -> bool {

    let success: bool;
    {
        let mut guard = chat_map.lock().unwrap();

        match guard.get_mut(&partner) {
            Some(clientinfo) => {
                if &partner[..] != &username[..]
                    && (clientinfo.partner == None
                        || clientinfo.partner == Some(username.to_string())) {
                    clientinfo.partner = Some(username.to_string());
                    success = true;
                } else {
                    success = false;
                }
            },
            None => success = false
        }
    }

    if success {
        let mut guard = chat_map.lock().unwrap();
        println!("Assigning partner {} to {}", partner, username);
        guard.get_mut(&username).unwrap().partner = Some(partner.to_string());
    }
    success
}

fn chat(stream: TcpStream,
        username: String,
        partner: String,
        sender_to_router: Sender<Message>,
        receiver_from_router: Receiver<Message>,
        chat_map: &Arc<Mutex<ChatMap>>) {

    let mut partner = partner.to_string();

    // Send messages
    {
        let username = username.clone();
        let chat_map = chat_map.clone();
        let stream = stream.try_clone().unwrap();
        let reader = BufReader::new(stream.try_clone().unwrap());
        thread::spawn(move|| {
            let mut lines = reader.lines();
            while let Some(Ok(line)) = lines.next() {
                println!("{}",line);

                let msg = Message::new(time::now().asctime().to_string(),
                                       username.to_string(),
                                       partner.to_string(),
                                       line.to_string());

                if &line[0..1] == "/" {
                    match parse_command(msg.content().to_string()) {
                        Command::Quit => {
                            println!("Quit command");
                            quit_conversation(&chat_map, username.to_string(), partner.to_string());
                            partner = choose_chat_partner(stream.try_clone().unwrap(), username.to_string(), &chat_map);
                        },
                        Command::DisplayAvailable => {
                            display_available(stream.try_clone().unwrap(), &chat_map, username.to_string());
                        },
                        Command::Logoff => println!("Logoff command"),
                        Command::Unrecognized => println!("Unrecognized command")
                    }
                } else {
                    sender_to_router.send(msg).unwrap();
                }
            }
        });
    }

    // Receive Messages
    {
        let username = username.clone();
        thread::spawn(move|| {
            loop {
                let stream = stream.try_clone().unwrap();
                match receiver_from_router.try_recv() {
                    Ok(msg) => {
                        println!("User {} received message: {}",
                            &username, msg.content());

                        receive_message(stream, msg);
                    },

                    Err(TryRecvError::Empty) => continue,

                    Err(TryRecvError::Disconnected) =>
                        panic!("User {} disconnected from router", &username)
                }
            }
        });
    }
}

fn receive_message(stream: TcpStream, msg: Message) {
    let mut stream = stream;
    let output = msg.from().to_string() + ": " + &msg.content()[..] + "\n";
    stream.write(&output.into_bytes()).unwrap();
}

fn quit_conversation(chat_map: &Arc<Mutex<ChatMap>>, username: String, partner: String) {
    let mut guard = chat_map.lock().unwrap();
    guard.get_mut(&username).unwrap().partner = None;
    guard.get_mut(&partner).unwrap().partner = None;
}

#[cfg(test)]
mod client_tests {

    use std::sync::{Arc, Mutex};
    use std::sync::mpsc::channel;
    use chatmap::{ChatMap, ClientInfo};
    use super::try_select_partner;

    #[test]
    fn try_select_partner_test_success_1() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));
    }

    #[test]
    fn try_select_partner_test_success_2() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Success: c and d become partners
        assert!(try_select_partner(&cm, "c".to_string(), "d".to_string()));
    }

    #[test]
    fn try_select_partner_test_succes_3() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Success: b can choose a when they are already partners
        //   (This allows someone to confirm a chat request)
        assert!(try_select_partner(&cm, "b".to_string(), "a".to_string()));
    }

    #[test]
    fn try_select_partner_test_fail_1() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Fail: b already has a partner
        assert!(!try_select_partner(&cm, "c".to_string(), "b".to_string()));
    }

    #[test]
    fn try_select_partner_test_fail_2() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Fail: Can't choose self as partner
        assert!(!try_select_partner(&cm, "c".to_string(), "c".to_string()));
    }

    #[test]
    fn try_select_partner_test_fail_3() {
        let cm = Arc::new(Mutex::new(fixture()));

        // Success: a and b become partners
        assert!(try_select_partner(&cm, "a".to_string(), "b".to_string()));

        // Success: c and d become partners
        assert!(try_select_partner(&cm, "c".to_string(), "d".to_string()));

        // Fail: c already has a partner
        assert!(!try_select_partner(&cm, "e".to_string(), "c".to_string()));

        // Fail: d already has a partner
        assert!(!try_select_partner(&cm, "e".to_string(), "d".to_string()));
    }

    fn fixture() -> ChatMap {
        let mut cm = ChatMap::new();
        let (sender_to_a, _) = channel();
        cm.insert("a".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_a
        });
        let (sender_to_b, _) = channel();
        cm.insert("b".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_b
        });
        let (sender_to_c, _) = channel();
        cm.insert("c".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_c
        });
        let (sender_to_d, _) = channel();
        cm.insert("d".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_d
        });
        let (sender_to_e, _) = channel();
        cm.insert("e".to_string(), ClientInfo{
            partner: None,
            sender_to_client: sender_to_e
        });
        cm
    }
}<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Statistics/Basic
#![feature(iter_arith)]
extern crate rand;

use rand::distributions::{IndependentSample, Range};

fn mean(data: &[f32]) -> Option<f32> {
    if data.is_empty() {
        None
    } else {
        let sum: f32 = data.iter().sum();
        Some(sum / data.len() as f32)
    }
}

fn variance(data: &[f32]) -> Option<f32> {
    if data.is_empty() {
        None
    } else {
        let mean = mean(data).unwrap();
        let mut sum = 0f32;
        for &x in data {
            sum += (x - mean).powi(2);
        }
        Some(sum / data.len() as f32)
    }
}

fn standard_deviation(data: &[f32]) -> Option<f32> {
    if data.is_empty() {
        None
    } else {
        let variance = variance(data).unwrap();
        Some(variance.sqrt())
    }
}

fn print_histogram(width: u32, data: &[f32]) {
    let mut histogram = [0; 10];
    let len = histogram.len() as f32;
    for &x in data {
        histogram[(x * len) as usize] += 1;
    }
    let max_frequency = *histogram.iter().max().unwrap() as f32;
    for (i, &frequency) in histogram.iter().enumerate() {
        let bar_width = frequency as f32 * width as f32 / max_frequency;
        print!("{:3.1}: ", i as f32 / len);
        for _ in 0..bar_width as usize {
            print!("*");
        }
        println!("");
    }
}

fn main() {
    let range = Range::new(0f32, 1f32);
    let mut rng = rand::thread_rng();

    for &number_of_samples in [1000, 10_000, 1_000_000].iter() {
        let mut data = vec![];
        for _ in 0..number_of_samples {
            let x = range.ind_sample(&mut rng);
            data.push(x);
        }
        println!("  Statistics for sample size {}", number_of_samples);
        println!("Mean:               {:?}", mean(&data));
        println!("Variance:           {:?}", variance(&data));
        println!("Standard deviation: {:?}", standard_deviation(&data));
        print_histogram(40, &data);
    }
}
<commit_msg>Basic statistics: add tests<commit_after>// http://rosettacode.org/wiki/Statistics/Basic
#![feature(iter_arith)]
extern crate rand;

use rand::distributions::{IndependentSample, Range};

pub fn mean(data: &[f32]) -> Option<f32> {
    if data.is_empty() {
        None
    } else {
        let sum: f32 = data.iter().sum();
        Some(sum / data.len() as f32)
    }
}

pub fn variance(data: &[f32]) -> Option<f32> {
    if data.is_empty() {
        None
    } else {
        let mean = mean(data).unwrap();
        let mut sum = 0f32;
        for &x in data {
            sum += (x - mean).powi(2);
        }
        Some(sum / data.len() as f32)
    }
}

pub fn standard_deviation(data: &[f32]) -> Option<f32> {
    if data.is_empty() {
        None
    } else {
        let variance = variance(data).unwrap();
        Some(variance.sqrt())
    }
}

fn print_histogram(width: u32, data: &[f32]) {
    let mut histogram = [0; 10];
    let len = histogram.len() as f32;
    for &x in data {
        histogram[(x * len) as usize] += 1;
    }
    let max_frequency = *histogram.iter().max().unwrap() as f32;
    for (i, &frequency) in histogram.iter().enumerate() {
        let bar_width = frequency as f32 * width as f32 / max_frequency;
        print!("{:3.1}: ", i as f32 / len);
        for _ in 0..bar_width as usize {
            print!("*");
        }
        println!("");
    }
}

fn main() {
    let range = Range::new(0f32, 1f32);
    let mut rng = rand::thread_rng();

    for &number_of_samples in [1000, 10_000, 1_000_000].iter() {
        let mut data = vec![];
        for _ in 0..number_of_samples {
            let x = range.ind_sample(&mut rng);
            data.push(x);
        }
        println!("  Statistics for sample size {}", number_of_samples);
        println!("Mean:               {:?}", mean(&data));
        println!("Variance:           {:?}", variance(&data));
        println!("Standard deviation: {:?}", standard_deviation(&data));
        print_histogram(40, &data);
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::{mean, variance, standard_deviation};

    fn approx(statistics: Option<f32>, value: f32) -> bool {
        (statistics.unwrap() - value).abs() <= f32::EPSILON
    }

    #[test]
    fn test_mean() {
        let empty: Vec<f32> = vec![];
        assert_eq!(mean(&empty), None);
        assert!(approx(mean(&[1.0]), 1.0));
        assert!(approx(mean(&[1.0, 3.0]), 2.0));
        assert!(approx(mean(&[1.0, 2.0, 3.0]), 2.0));
    }

    #[test]
    fn test_variance() {
        let empty: Vec<f32> = vec![];
        assert_eq!(variance(&empty), None);
        assert!(approx(variance(&[0.0]), 0.0));
        assert!(approx(variance(&[1.0, 1.0, 1.0]), 0.0));
        assert!(approx(variance(&[1.0, 2.0, 3.0]), 2.0 / 3.0));
    }

    #[test]
    fn test_standard_deviation() {
        let empty: Vec<f32> = vec![];
        assert_eq!(standard_deviation(&empty), None);
        assert!(approx(standard_deviation(&[0.0]), 0.0));
        assert!(approx(standard_deviation(&[1.0, 1.0, 1.0]), 0.0));
        assert!(approx(standard_deviation(&[1.0, 2.0, 3.0]),
                       (2.0f32 / 3.0f32).sqrt()));
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;

use error::{WebDriverResult, WebDriverError, ErrorStatus};

pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";

#[derive(Clone, Debug, PartialEq, RustcEncodable)]
pub struct Date(pub u64);

impl Date {
    pub fn new(timestamp: u64) -> Date {
        Date(timestamp)
    }
}

impl ToJson for Date {
    fn to_json(&self) -> Json {
        let &Date(x) = self;
        x.to_json()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Nullable<T: ToJson> {
    Value(T),
    Null
}

impl<T: ToJson> Nullable<T> {
     pub fn is_null(&self) -> bool {
        match *self {
            Nullable::Value(_) => false,
            Nullable::Null => true
        }
    }

     pub fn is_value(&self) -> bool {
        match *self {
            Nullable::Value(_) => true,
            Nullable::Null => false
        }
    }

    pub fn map<F, U: ToJson>(self, f: F) -> Nullable<U>
        where F: FnOnce(T) -> U {
        match self {
            Nullable::Value(val) => Nullable::Value(f(val)),
            Nullable::Null => Nullable::Null
        }
    }
}

impl<T: ToJson> Nullable<T> {
    //This is not very pretty
    pub fn from_json<F: FnOnce(&Json) -> WebDriverResult<T>>(value: &Json, f: F) -> WebDriverResult<Nullable<T>> {
        if value.is_null() {
            Ok(Nullable::Null)
        } else {
            Ok(Nullable::Value(try!(f(value))))
        }
    }
}

impl<T: ToJson> ToJson for Nullable<T> {
    fn to_json(&self) -> Json {
        match *self {
            Nullable::Value(ref x) => x.to_json(),
            Nullable::Null => Json::Null
        }
    }
}

impl<T: ToJson> Encodable for Nullable<T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Nullable::Value(ref x) => x.to_json().encode(s),
            Nullable::Null => s.emit_option_none()
        }
    }
}

impl<T: ToJson> Into<Option<T>> for Nullable<T> {
    fn into(self) -> Option<T> {
        match self {
            Nullable::Value(val) => Some(val),
            Nullable::Null => None
        }
    }
}

impl<T: ToJson> From<Option<T>> for Nullable<T> {
    fn from(option: Option<T>) -> Nullable<T> {
        match option {
            Some(val) => Nullable::Value(val),
            None => Nullable::Null,
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct WebElement {
    pub id: String
}

impl WebElement {
    pub fn new(id: String) -> WebElement {
        WebElement {
            id: id
        }
    }

    pub fn from_json(data: &Json) -> WebDriverResult<WebElement> {
        let object = try_opt!(data.as_object(),
                              ErrorStatus::InvalidArgument,
                              "Could not convert webelement to object");
        let id_value = try_opt!(object.get(ELEMENT_KEY),
                                ErrorStatus::InvalidArgument,
                                "Could not find webelement key");

        let id = try_opt!(id_value.as_string(),
                          ErrorStatus::InvalidArgument,
                          "Could not convert web element to string").to_string();

        Ok(WebElement::new(id))
    }
}

impl ToJson for WebElement {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert(ELEMENT_KEY.to_string(), self.id.to_json());
        Json::Object(data)
    }
}

impl <T> From<T> for WebElement
    where T: Into<String> {
    fn from(data: T) -> WebElement {
        WebElement::new(data.into())
    }
}

#[derive(Debug, PartialEq)]
pub enum FrameId {
    Short(u16),
    Element(WebElement),
    Null
}

impl FrameId {
    pub fn from_json(data: &Json) -> WebDriverResult<FrameId> {
        match data {
            &Json::U64(x) => {
                if x > u16::max_value() as u64 || x < u16::min_value() as u64 {
                    return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                                   "frame id out of range"))
                };
                Ok(FrameId::Short(x as u16))
            },
            &Json::Null => Ok(FrameId::Null),
            &Json::Object(_) => Ok(FrameId::Element(
                try!(WebElement::from_json(data)))),
            _ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                         "frame id has unexpected type"))
        }
    }
}

impl ToJson for FrameId {
    fn to_json(&self) -> Json {
        match *self {
            FrameId::Short(x) => {
                Json::U64(x as u64)
            },
            FrameId::Element(ref x) => {
                Json::String(x.id.clone())
            },
            FrameId::Null => {
                Json::Null
            }
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum LocatorStrategy {
    CSSSelector,
    LinkText,
    PartialLinkText,
    XPath,
}

impl LocatorStrategy {
    pub fn from_json(body: &Json) -> WebDriverResult<LocatorStrategy> {
        match try_opt!(body.as_string(),
                       ErrorStatus::InvalidArgument,
                       "Expected locator strategy as string") {
            "css selector" => Ok(LocatorStrategy::CSSSelector),
            "link text" => Ok(LocatorStrategy::LinkText),
            "partial link text" => Ok(LocatorStrategy::PartialLinkText),
            "xpath" => Ok(LocatorStrategy::XPath),
            x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                         format!("Unknown locator strategy {}", x)))
        }
    }
}

impl ToJson for LocatorStrategy {
    fn to_json(&self) -> Json {
        Json::String(match *self {
            LocatorStrategy::CSSSelector => "css selector",
            LocatorStrategy::LinkText => "link text",
            LocatorStrategy::PartialLinkText => "partial link text",
            LocatorStrategy::XPath => "xpath"
        }.to_string())
    }
}

/// The top-level browsing context has an associated window state which
/// describes what visibility state its OS widget window is in.
///
/// The default state is [`Normal`].
///
/// [`normal`]: #variant.Normal
#[derive(Debug)]
pub enum WindowState {
    /// The window is maximized.
    Maximized,
    /// The window is iconified.
    Minimized,
    /// The window is shown normally.
    Normal,
    /// The window is in full screen mode.
    Fullscreen,
}

impl WindowState {
    pub fn from_json(body: &Json) -> WebDriverResult<WindowState> {
        use self::WindowState::*;
        let s = try_opt!(
            body.as_string(),
            ErrorStatus::InvalidArgument,
            "Expecetd window state as string"
        );
        match s {
            "maximized" => Ok(Maximized),
            "minimized" => Ok(Minimized),
            "normal" => Ok(Normal),
            "fullscreen" => Ok(Fullscreen),
            x => Err(WebDriverError::new(
                ErrorStatus::InvalidArgument,
                format!("Unknown window state {}", x),
            )),
        }
    }
}

impl ToJson for WindowState {
    fn to_json(&self) -> Json {
        use self::WindowState::*;
        let state = match *self {
            Maximized => "maximized",
            Minimized => "minimized",
            Normal => "normal",
            Fullscreen => "fullscreen",
        };
        Json::String(state.to_string())
    }
}
<commit_msg>Add Tag Name as a valid location strategy. (#118)<commit_after>use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;

use error::{WebDriverResult, WebDriverError, ErrorStatus};

pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";

#[derive(Clone, Debug, PartialEq, RustcEncodable)]
pub struct Date(pub u64);

impl Date {
    pub fn new(timestamp: u64) -> Date {
        Date(timestamp)
    }
}

impl ToJson for Date {
    fn to_json(&self) -> Json {
        let &Date(x) = self;
        x.to_json()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Nullable<T: ToJson> {
    Value(T),
    Null
}

impl<T: ToJson> Nullable<T> {
     pub fn is_null(&self) -> bool {
        match *self {
            Nullable::Value(_) => false,
            Nullable::Null => true
        }
    }

     pub fn is_value(&self) -> bool {
        match *self {
            Nullable::Value(_) => true,
            Nullable::Null => false
        }
    }

    pub fn map<F, U: ToJson>(self, f: F) -> Nullable<U>
        where F: FnOnce(T) -> U {
        match self {
            Nullable::Value(val) => Nullable::Value(f(val)),
            Nullable::Null => Nullable::Null
        }
    }
}

impl<T: ToJson> Nullable<T> {
    //This is not very pretty
    pub fn from_json<F: FnOnce(&Json) -> WebDriverResult<T>>(value: &Json, f: F) -> WebDriverResult<Nullable<T>> {
        if value.is_null() {
            Ok(Nullable::Null)
        } else {
            Ok(Nullable::Value(try!(f(value))))
        }
    }
}

impl<T: ToJson> ToJson for Nullable<T> {
    fn to_json(&self) -> Json {
        match *self {
            Nullable::Value(ref x) => x.to_json(),
            Nullable::Null => Json::Null
        }
    }
}

impl<T: ToJson> Encodable for Nullable<T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Nullable::Value(ref x) => x.to_json().encode(s),
            Nullable::Null => s.emit_option_none()
        }
    }
}

impl<T: ToJson> Into<Option<T>> for Nullable<T> {
    fn into(self) -> Option<T> {
        match self {
            Nullable::Value(val) => Some(val),
            Nullable::Null => None
        }
    }
}

impl<T: ToJson> From<Option<T>> for Nullable<T> {
    fn from(option: Option<T>) -> Nullable<T> {
        match option {
            Some(val) => Nullable::Value(val),
            None => Nullable::Null,
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct WebElement {
    pub id: String
}

impl WebElement {
    pub fn new(id: String) -> WebElement {
        WebElement {
            id: id
        }
    }

    pub fn from_json(data: &Json) -> WebDriverResult<WebElement> {
        let object = try_opt!(data.as_object(),
                              ErrorStatus::InvalidArgument,
                              "Could not convert webelement to object");
        let id_value = try_opt!(object.get(ELEMENT_KEY),
                                ErrorStatus::InvalidArgument,
                                "Could not find webelement key");

        let id = try_opt!(id_value.as_string(),
                          ErrorStatus::InvalidArgument,
                          "Could not convert web element to string").to_string();

        Ok(WebElement::new(id))
    }
}

impl ToJson for WebElement {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert(ELEMENT_KEY.to_string(), self.id.to_json());
        Json::Object(data)
    }
}

impl <T> From<T> for WebElement
    where T: Into<String> {
    fn from(data: T) -> WebElement {
        WebElement::new(data.into())
    }
}

#[derive(Debug, PartialEq)]
pub enum FrameId {
    Short(u16),
    Element(WebElement),
    Null
}

impl FrameId {
    pub fn from_json(data: &Json) -> WebDriverResult<FrameId> {
        match data {
            &Json::U64(x) => {
                if x > u16::max_value() as u64 || x < u16::min_value() as u64 {
                    return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                                   "frame id out of range"))
                };
                Ok(FrameId::Short(x as u16))
            },
            &Json::Null => Ok(FrameId::Null),
            &Json::Object(_) => Ok(FrameId::Element(
                try!(WebElement::from_json(data)))),
            _ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
                                         "frame id has unexpected type"))
        }
    }
}

impl ToJson for FrameId {
    fn to_json(&self) -> Json {
        match *self {
            FrameId::Short(x) => {
                Json::U64(x as u64)
            },
            FrameId::Element(ref x) => {
                Json::String(x.id.clone())
            },
            FrameId::Null => {
                Json::Null
            }
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum LocatorStrategy {
    CSSSelector,
    LinkText,
    PartialLinkText,
    TagName,
    XPath,
}

impl LocatorStrategy {
    pub fn from_json(body: &Json) -> WebDriverResult<LocatorStrategy> {
        match try_opt!(body.as_string(),
                       ErrorStatus::InvalidArgument,
                       "Expected locator strategy as string") {
            "css selector" => Ok(LocatorStrategy::CSSSelector),
            "link text" => Ok(LocatorStrategy::LinkText),
            "partial link text" => Ok(LocatorStrategy::PartialLinkText),
            "tag name" => Ok(LocatorStrategy::TagName),
            "xpath" => Ok(LocatorStrategy::XPath),
            x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                         format!("Unknown locator strategy {}", x)))
        }
    }
}

impl ToJson for LocatorStrategy {
    fn to_json(&self) -> Json {
        Json::String(match *self {
            LocatorStrategy::CSSSelector => "css selector",
            LocatorStrategy::LinkText => "link text",
            LocatorStrategy::PartialLinkText => "partial link text",
            LocatorStrategy::TagName => "tag name",
            LocatorStrategy::XPath => "xpath"
        }.to_string())
    }
}

/// The top-level browsing context has an associated window state which
/// describes what visibility state its OS widget window is in.
///
/// The default state is [`Normal`].
///
/// [`normal`]: #variant.Normal
#[derive(Debug)]
pub enum WindowState {
    /// The window is maximized.
    Maximized,
    /// The window is iconified.
    Minimized,
    /// The window is shown normally.
    Normal,
    /// The window is in full screen mode.
    Fullscreen,
}

impl WindowState {
    pub fn from_json(body: &Json) -> WebDriverResult<WindowState> {
        use self::WindowState::*;
        let s = try_opt!(
            body.as_string(),
            ErrorStatus::InvalidArgument,
            "Expecetd window state as string"
        );
        match s {
            "maximized" => Ok(Maximized),
            "minimized" => Ok(Minimized),
            "normal" => Ok(Normal),
            "fullscreen" => Ok(Fullscreen),
            x => Err(WebDriverError::new(
                ErrorStatus::InvalidArgument,
                format!("Unknown window state {}", x),
            )),
        }
    }
}

impl ToJson for WindowState {
    fn to_json(&self) -> Json {
        use self::WindowState::*;
        let state = match *self {
            Maximized => "maximized",
            Minimized => "minimized",
            Normal => "normal",
            Fullscreen => "fullscreen",
        };
        Json::String(state.to_string())
    }
}
<|endoftext|>


<commit_before>//! Contains common types and functions used throughout the library.

use std::fmt;

/// Represents a position inside some textual document.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct TextPosition {
    /// Row, counting from 0
    pub row: u64,
    /// Column, counting from 0
    pub column: u64,
}

impl TextPosition {
    /// Creates a new position initialized to the beginning of the document
    #[inline]
    pub fn new() -> TextPosition {
        TextPosition { row: 0, column: 0 }
    }

    /// Advances the position in a line
    #[inline]
    pub fn advance(&mut self, count: u8) {
        self.column += count as u64;
    }

    /// Advances the position in a line to the next tab position
    #[inline]
    pub fn advance_to_tab(&mut self, width: u8) {
        let width = width as u64;
        self.column += width - self.column % width
    }

    /// Advances the position to the beginning of the next line
    #[inline]
    pub fn new_line(&mut self) {
        self.column = 0;
        self.row += 1;
    }
}

impl fmt::Debug for TextPosition {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.row + 1, self.column + 1)
    }
}

impl fmt::Display for TextPosition {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.row + 1, self.column + 1)
    }
}

/// Get the position in the document corresponding to the object
///
/// This trait is implemented by parsers, lexers and errors.
pub trait Position {
    /// Returns the current position or a position corresponding to the object.
    fn position(&self) -> TextPosition;
}

impl Position for TextPosition {
    #[inline]
    fn position(&self) -> TextPosition {
        *self
    }
}

/// XML version enumeration.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML version 1.0.
    Version10,

    /// XML version 1.1.
    Version11
}

impl fmt::Display for XmlVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            XmlVersion::Version10 => write!(f, "1.0"),
            XmlVersion::Version11 => write!(f, "1.1")
        }
    }
}

/// Checks whether the given character is a white space character (`S`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_whitespace_char(c: char) -> bool {
    match c {
        '\x20' | '\x09' | '\x0d' | '\x0a' => true,
        _ => false
    }
}

/// Checks whether the given character is a name start character (`NameStartChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_start_char(c: char) -> bool {
    match c {
        ':' | 'A'...'Z' | '_' | 'a'...'z' |
        '\u{C0}'...'\u{D6}' | '\u{D8}'...'\u{F6}' | '\u{F8}'...'\u{2FF}' |
        '\u{370}'...'\u{37D}' | '\u{37F}'...'\u{1FFF}' |
        '\u{200C}'...'\u{200D}' | '\u{2070}'...'\u{218F}' |
        '\u{2C00}'...'\u{2FEF}' | '\u{3001}'...'\u{D7FF}' |
        '\u{F900}'...'\u{FDCF}' | '\u{FDF0}'...'\u{FFFD}' |
        '\u{10000}'...'\u{EFFFF}' => true,
        _ => false
    }
}

/// Checks whether the given character is a name character (`NameChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_char(c: char) -> bool {
    match c {
        _ if is_name_start_char(c) => true,
        '-' | '.' | '0'...'9' | '\u{B7}' |
        '\u{300}'...'\u{3F6}' | '\u{203F}'...'\u{2040}' => true,
        _ => false
    }
}
<commit_msg>Add missing Debug impl for XmlVersion<commit_after>//! Contains common types and functions used throughout the library.

use std::fmt;

/// Represents a position inside some textual document.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct TextPosition {
    /// Row, counting from 0
    pub row: u64,
    /// Column, counting from 0
    pub column: u64,
}

impl TextPosition {
    /// Creates a new position initialized to the beginning of the document
    #[inline]
    pub fn new() -> TextPosition {
        TextPosition { row: 0, column: 0 }
    }

    /// Advances the position in a line
    #[inline]
    pub fn advance(&mut self, count: u8) {
        self.column += count as u64;
    }

    /// Advances the position in a line to the next tab position
    #[inline]
    pub fn advance_to_tab(&mut self, width: u8) {
        let width = width as u64;
        self.column += width - self.column % width
    }

    /// Advances the position to the beginning of the next line
    #[inline]
    pub fn new_line(&mut self) {
        self.column = 0;
        self.row += 1;
    }
}

impl fmt::Debug for TextPosition {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.row + 1, self.column + 1)
    }
}

impl fmt::Display for TextPosition {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.row + 1, self.column + 1)
    }
}

/// Get the position in the document corresponding to the object
///
/// This trait is implemented by parsers, lexers and errors.
pub trait Position {
    /// Returns the current position or a position corresponding to the object.
    fn position(&self) -> TextPosition;
}

impl Position for TextPosition {
    #[inline]
    fn position(&self) -> TextPosition {
        *self
    }
}

/// XML version enumeration.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML version 1.0.
    Version10,

    /// XML version 1.1.
    Version11
}

impl fmt::Display for XmlVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            XmlVersion::Version10 => write!(f, "1.0"),
            XmlVersion::Version11 => write!(f, "1.1")
        }
    }
}

impl fmt::Debug for XmlVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

/// Checks whether the given character is a white space character (`S`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_whitespace_char(c: char) -> bool {
    match c {
        '\x20' | '\x09' | '\x0d' | '\x0a' => true,
        _ => false
    }
}

/// Checks whether the given character is a name start character (`NameStartChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_start_char(c: char) -> bool {
    match c {
        ':' | 'A'...'Z' | '_' | 'a'...'z' |
        '\u{C0}'...'\u{D6}' | '\u{D8}'...'\u{F6}' | '\u{F8}'...'\u{2FF}' |
        '\u{370}'...'\u{37D}' | '\u{37F}'...'\u{1FFF}' |
        '\u{200C}'...'\u{200D}' | '\u{2070}'...'\u{218F}' |
        '\u{2C00}'...'\u{2FEF}' | '\u{3001}'...'\u{D7FF}' |
        '\u{F900}'...'\u{FDCF}' | '\u{FDF0}'...'\u{FFFD}' |
        '\u{10000}'...'\u{EFFFF}' => true,
        _ => false
    }
}

/// Checks whether the given character is a name character (`NameChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_char(c: char) -> bool {
    match c {
        _ if is_name_start_char(c) => true,
        '-' | '.' | '0'...'9' | '\u{B7}' |
        '\u{300}'...'\u{3F6}' | '\u{203F}'...'\u{2040}' => true,
        _ => false
    }
}
<|endoftext|>


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

extern crate log;
extern crate toml;
extern crate rpcperf_workload as workload;

use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use toml::Parser;
use toml::Value;
use toml::Value::{Array, Table};
use workload::{Parameter, Style, Type};

type CResult<T> = Result<T, String>;

#[derive(Clone)]
pub struct BenchmarkWorkload {
    pub rate: usize,
    pub method: String,
    pub parameters: Vec<Parameter>,
}

impl Default for BenchmarkWorkload {
    fn default() -> BenchmarkWorkload {
        BenchmarkWorkload {
            rate: 0,
            method: "get".to_owned(),
            parameters: Vec::<Parameter>::new(),
        }
    }
}

pub struct BenchmarkConfig {
    pub connections: usize,
    pub threads: usize,
    pub duration: usize,
    pub windows: usize,
    pub protocol: String,
    pub tcp_nodelay: bool,
    pub ipv4: bool,
    pub ipv6: bool,
    pub workloads: Vec<BenchmarkWorkload>,
}

impl Default for BenchmarkConfig {
    fn default() -> BenchmarkConfig {
        BenchmarkConfig {
            connections: 1,
            threads: 1,
            duration: 60,
            windows: 5,
            protocol: "memcache".to_owned(),
            tcp_nodelay: false,
            ipv4: true,
            ipv6: true,
            workloads: Vec::new(),
        }
    }
}

pub fn load_config(path: &str) -> Result<BenchmarkConfig, String> {
    let mut f = File::open(&path).unwrap();

    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    load_config_str(path, &s)
}

pub fn load_config_str(config_name: &str, config: &str) -> Result<BenchmarkConfig, String> {
    let mut p = Parser::new(config);

    match p.parse() {
        Some(table) => {
            debug!("toml parsed successfully. creating config");

            let mut config: BenchmarkConfig = Default::default();

            if let Some(&Table(ref general)) = table.get("general") {
                if let Some(connections) = general.get("connections")
                                                  .and_then(|k| k.as_integer()) {
                    config.connections = connections as usize;
                };
                if let Some(threads) = general.get("threads").and_then(|k| k.as_integer()) {
                    config.threads = threads as usize;
                }
                if let Some(duration) = general.get("duration")
                                               .and_then(|k| k.as_integer()) {
                    config.duration = duration as usize;
                }
                if let Some(windows) = general.get("windows").and_then(|k| k.as_integer()) {
                    config.windows = windows as usize;
                }
                if let Some(protocol) = general.get("protocol").and_then(|k| k.as_str()) {
                    config.protocol = protocol.to_owned();
                }
                if let Some(tcp_nodelay) = general.get("tcp-nodelay")
                                                  .and_then(|k| k.as_bool()) {
                    config.tcp_nodelay = tcp_nodelay;
                }
                if let Some(ipv4) = general.get("ipv4").and_then(|k| k.as_bool()) {
                    config.ipv4 = ipv4;
                }
                if let Some(ipv6) = general.get("ipv6").and_then(|k| k.as_bool()) {
                    config.ipv6 = ipv6;
                }
            }

            match table.get("workload") {
                None => return Err("no workload section".to_owned()),
                Some(&Array(ref workloads)) => {
                    for (i, workload) in workloads.iter().enumerate() {
                        if let &Table(ref workload) = workload {
                            let w = try!(extract_workload(i, workload));
                            config.workloads.push(w);
                        } else {
                            return Err("malformed config: workload must be a struct".to_owned());
                        }
                    }
                }
                Some(_) => return Err("malformed config: workloads must be an array".to_owned()),
            }

            Ok(config)
        }
        None => {
            for err in &p.errors {
                let (loline, locol) = p.to_linecol(err.lo);
                let (hiline, hicol) = p.to_linecol(err.hi);
                println!("{}:{}:{}-{}:{} error: {}",
                         config_name,
                         loline,
                         locol,
                         hiline,
                         hicol,
                         err.desc);
            }
            Err("failed to load config".to_owned())
        }
    }
}

fn extract_workload(i: usize, workload: &BTreeMap<String,Value>) -> CResult<BenchmarkWorkload> {
    let mut w: BenchmarkWorkload = Default::default();
    if let Some(method) = workload.get("method").and_then(|k| k.as_str()) {
        w.method = method.to_owned();
    }
    if let Some(rate) = workload.get("rate").and_then(|k| k.as_integer()) {
        w.rate = rate as usize;
    }

    match workload.get("parameter") {
        Some(&Array(ref params)) => {
            for param in params {
                match param {
                    &Table(ref parameter) => {
                        let p = try!(extract_parameters(i, parameter));
                        w.parameters.push(p);
                    }
                    _ => {
                        return Err("malformed config: a parameter must be a struct".to_owned());
                    }
                }
            }

        }
        Some(_) => return Err("malformed config: 'parameter' must be an array".to_owned()),
        None => {}
    }
    Ok(w)
}

fn extract_parameters(i: usize, parameter: &BTreeMap<String,Value>) -> CResult<Parameter> {

    let mut p = Parameter::default();
    p.id = match parameter.get("id")
                          .and_then(|k| k.as_integer()) {
        Some(s) => Some(s as i16),
        None => None,
    };

    p.ptype = match parameter.get("type")
                             .and_then(|k| k.as_str()) {
        Some("stop") => Type::Stop,
        Some("void") => Type::Void,
        Some("bool") => Type::Bool,
        Some("byte") => Type::Byte,
        Some("double") => Type::Double,
        Some("i16") => Type::Int16,
        Some("i32") => Type::Int32,
        Some("i64") => Type::Int64,
        Some("string") => Type::String,
        Some("struct") => Type::Struct,
        Some("map") => Type::Map,
        Some("set") => Type::Set,
        Some("list") => {
            Type::List(parameter.get("contains")
                                .and_then(|k| k.as_str())
                                .unwrap()
                                .to_owned())
        }
        Some(_) => Type::None,
        None => Type::None,
    };

    p.style = match parameter.get("style")
                               .and_then(|k| k.as_str()) {
        Some("random") => Style::Random,
        Some("static") => Style::Static,
        None => Style::Static,
        Some(other) => return Err(format!("bad parameter style: {}", other)),
    };

    p.seed = match parameter.get("seed")
                            .and_then(|k| k.as_integer()) {
        Some(s) => s as usize,
        None => i,
    };
    p.size = match parameter.get("size")
                            .and_then(|k| k.as_integer()) {
        Some(s) => s as usize,
        None => 1,
    };
    p.regenerate = match parameter.get("regenerate")
                                  .and_then(|k| k.as_bool()) {
        Some(s) => s,
        None => false,
    };

    Ok(p)
}

#[test]
fn test_load_config() {
    let config_str = include_str!("../configs/thrift_calc.toml");
    let workload = load_config_str("thrift_calc.toml", config_str).unwrap();

    assert_eq!(workload.protocol, "thrift");
    assert_eq!(workload.workloads.len(), 3);

    let w0 = &workload.workloads[0];
    // Check the first workload
    assert_eq!(w0.method, "ping");
    assert_eq!(w0.rate, 1);
    assert_eq!(w0.parameters.len(), 0);

    let w2 = &workload.workloads[2];
    // check the second workload
    assert_eq!(w2.method, "calculate");
    assert_eq!(w2.rate, 1);
    assert_eq!(w2.parameters.len(), 6);

    // Check that the first parameter of the second workload was parsed correctly
    assert_eq!(w2.parameters[0].id, Some(1));
    assert_eq!(w2.parameters[0].ptype, Type::Int32);
    assert_eq!(w2.parameters[0].style, Style::Static);
    assert_eq!(w2.parameters[0].regenerate, false);

    // Check that the last parameter was also parsed correctly
    assert_eq!(w2.parameters[5].id, None);
    assert_eq!(w2.parameters[5].ptype, Type::Stop);
    assert_eq!(w2.parameters[5].style, Style::Static);
    assert_eq!(w2.parameters[5].regenerate, false);
}
<commit_msg>Fix doc strings and make unknown parameter types an error<commit_after>//  rpc-perf - RPC Performance Testing
//  Copyright 2015 Twitter, Inc
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

extern crate log;
extern crate toml;
extern crate rpcperf_workload as workload;

use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use toml::Parser;
use toml::Value;
use toml::Value::{Array, Table};
use workload::{Parameter, Style, Type};

type CResult<T> = Result<T, String>;

#[derive(Clone)]
pub struct BenchmarkWorkload {
    pub rate: usize,
    pub method: String,
    pub parameters: Vec<Parameter>,
}

impl Default for BenchmarkWorkload {
    fn default() -> BenchmarkWorkload {
        BenchmarkWorkload {
            rate: 0,
            method: "get".to_owned(),
            parameters: Vec::<Parameter>::new(),
        }
    }
}

pub struct BenchmarkConfig {
    pub connections: usize,
    pub threads: usize,
    pub duration: usize,
    pub windows: usize,
    pub protocol: String,
    pub tcp_nodelay: bool,
    pub ipv4: bool,
    pub ipv6: bool,
    pub workloads: Vec<BenchmarkWorkload>,
}

impl Default for BenchmarkConfig {
    fn default() -> BenchmarkConfig {
        BenchmarkConfig {
            connections: 1,
            threads: 1,
            duration: 60,
            windows: 5,
            protocol: "memcache".to_owned(),
            tcp_nodelay: false,
            ipv4: true,
            ipv6: true,
            workloads: Vec::new(),
        }
    }
}

pub fn load_config(path: &str) -> Result<BenchmarkConfig, String> {
    let mut f = File::open(&path).unwrap();

    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    load_config_str(path, &s)
}

pub fn load_config_str(config_name: &str, config: &str) -> Result<BenchmarkConfig, String> {
    let mut p = Parser::new(config);

    match p.parse() {
        Some(table) => {
            debug!("toml parsed successfully. creating config");

            let mut config: BenchmarkConfig = Default::default();

            if let Some(&Table(ref general)) = table.get("general") {
                if let Some(connections) = general.get("connections")
                                                  .and_then(|k| k.as_integer()) {
                    config.connections = connections as usize;
                };
                if let Some(threads) = general.get("threads").and_then(|k| k.as_integer()) {
                    config.threads = threads as usize;
                }
                if let Some(duration) = general.get("duration")
                                               .and_then(|k| k.as_integer()) {
                    config.duration = duration as usize;
                }
                if let Some(windows) = general.get("windows").and_then(|k| k.as_integer()) {
                    config.windows = windows as usize;
                }
                if let Some(protocol) = general.get("protocol").and_then(|k| k.as_str()) {
                    config.protocol = protocol.to_owned();
                }
                if let Some(tcp_nodelay) = general.get("tcp-nodelay")
                                                  .and_then(|k| k.as_bool()) {
                    config.tcp_nodelay = tcp_nodelay;
                }
                if let Some(ipv4) = general.get("ipv4").and_then(|k| k.as_bool()) {
                    config.ipv4 = ipv4;
                }
                if let Some(ipv6) = general.get("ipv6").and_then(|k| k.as_bool()) {
                    config.ipv6 = ipv6;
                }
            }

            match table.get("workload") {
                None => return Err("no workload section".to_owned()),
                Some(&Array(ref workloads)) => {
                    for (i, workload) in workloads.iter().enumerate() {
                        if let &Table(ref workload) = workload {
                            let w = try!(extract_workload(i, workload));
                            config.workloads.push(w);
                        } else {
                            return Err("malformed config: workload must be a struct".to_owned());
                        }
                    }
                }
                Some(_) => return Err("malformed config: workloads must be an array".to_owned()),
            }

            Ok(config)
        }
        None => {
            for err in &p.errors {
                let (loline, locol) = p.to_linecol(err.lo);
                let (hiline, hicol) = p.to_linecol(err.hi);
                println!("{}:{}:{}-{}:{} error: {}",
                         config_name,
                         loline,
                         locol,
                         hiline,
                         hicol,
                         err.desc);
            }
            Err("failed to load config".to_owned())
        }
    }
}

fn extract_workload(i: usize, workload: &BTreeMap<String,Value>) -> CResult<BenchmarkWorkload> {
    let mut w: BenchmarkWorkload = Default::default();
    if let Some(method) = workload.get("method").and_then(|k| k.as_str()) {
        w.method = method.to_owned();
    }
    if let Some(rate) = workload.get("rate").and_then(|k| k.as_integer()) {
        w.rate = rate as usize;
    }

    match workload.get("parameter") {
        Some(&Array(ref params)) => {
            for param in params {
                match param {
                    &Table(ref parameter) => {
                        let p = try!(extract_parameters(i, parameter));
                        w.parameters.push(p);
                    }
                    _ => {
                        return Err("malformed config: a parameter must be a struct".to_owned());
                    }
                }
            }

        }
        Some(_) => return Err("malformed config: 'parameter' must be an array".to_owned()),
        None => {}
    }
    Ok(w)
}

fn extract_parameters(i: usize, parameter: &BTreeMap<String,Value>) -> CResult<Parameter> {

    let mut p = Parameter::default();
    p.id = match parameter.get("id")
                          .and_then(|k| k.as_integer()) {
        Some(s) => Some(s as i16),
        None => None,
    };

    p.ptype = match parameter.get("type")
                             .and_then(|k| k.as_str()) {
        Some("stop") => Type::Stop,
        Some("void") => Type::Void,
        Some("bool") => Type::Bool,
        Some("byte") => Type::Byte,
        Some("double") => Type::Double,
        Some("i16") => Type::Int16,
        Some("i32") => Type::Int32,
        Some("i64") => Type::Int64,
        Some("string") => Type::String,
        Some("struct") => Type::Struct,
        Some("map") => Type::Map,
        Some("set") => Type::Set,
        Some("list") => {
            Type::List(parameter.get("contains")
                                .and_then(|k| k.as_str())
                                .unwrap()
                                .to_owned())
        }
        Some(unknown) => return Err(format!("unknown parameter type: {}", unknown)),
        None => Type::None,
    };

    p.style = match parameter.get("style")
                               .and_then(|k| k.as_str()) {
        Some("random") => Style::Random,
        Some("static") => Style::Static,
        None => Style::Static,
        Some(other) => return Err(format!("bad parameter style: {}", other)),
    };

    p.seed = match parameter.get("seed")
                            .and_then(|k| k.as_integer()) {
        Some(s) => s as usize,
        None => i,
    };
    p.size = match parameter.get("size")
                            .and_then(|k| k.as_integer()) {
        Some(s) => s as usize,
        None => 1,
    };
    p.regenerate = match parameter.get("regenerate")
                                  .and_then(|k| k.as_bool()) {
        Some(s) => s,
        None => false,
    };

    Ok(p)
}

#[test]
fn test_load_config() {
    let config_str = include_str!("../configs/thrift_calc.toml");
    let workload = load_config_str("thrift_calc.toml", config_str).unwrap();

    assert_eq!(workload.protocol, "thrift");
    assert_eq!(workload.workloads.len(), 3);

    let w0 = &workload.workloads[0];
    // Check the first workload
    assert_eq!(w0.method, "ping");
    assert_eq!(w0.rate, 1);
    assert_eq!(w0.parameters.len(), 0);

    let w2 = &workload.workloads[2];
    // check the third workload
    assert_eq!(w2.method, "calculate");
    assert_eq!(w2.rate, 1);
    assert_eq!(w2.parameters.len(), 6);

    // Check that the first parameter of the third workload was parsed correctly
    assert_eq!(w2.parameters[0].id, Some(1));
    assert_eq!(w2.parameters[0].ptype, Type::Int32);
    assert_eq!(w2.parameters[0].style, Style::Static);
    assert_eq!(w2.parameters[0].regenerate, false);

    // Check that the last parameter was also parsed correctly
    assert_eq!(w2.parameters[5].id, None);
    assert_eq!(w2.parameters[5].ptype, Type::Stop);
    assert_eq!(w2.parameters[5].style, Style::Static);
    assert_eq!(w2.parameters[5].regenerate, false);
}
<|endoftext|>