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

use std::thread;
use std::cell::RefCell;
use CHashMap;

#[test]
fn test_create_capacity_zero() {
    let mut m = CHashMap::with_capacity(0);

    assert!(m.insert(1, 1).is_none());

    assert!(m.contains_key(&1));
    assert!(!m.contains_key(&0));
}

#[test]
fn test_insert() {
    let mut m = CHashMap::new();
    assert_eq!(m.len(), 0);
    assert!(m.insert(1, 2).is_none());
    assert_eq!(m.len(), 1);
    assert!(m.insert(2, 4).is_none());
    assert_eq!(m.len(), 2);
    assert_eq!(*m.get(&1).unwrap(), 2);
    assert_eq!(*m.get(&2).unwrap(), 4);
}

thread_local! { static DROP_VECTOR: RefCell<Vec<isize>> = RefCell::new(Vec::new()) }

#[derive(Hash, PartialEq, Eq)]
struct Dropable {
    k: usize
}

impl Dropable {
    fn new(k: usize) -> Dropable {
        DROP_VECTOR.with(|slot| {
            slot.borrow_mut()[k] += 1;
        });

        Dropable { k: k }
    }
}

impl Drop for Dropable {
    fn drop(&mut self) {
        DROP_VECTOR.with(|slot| {
            slot.borrow_mut()[self.k] -= 1;
        });
    }
}

impl Clone for Dropable {
    fn clone(&self) -> Dropable {
        Dropable::new(self.k)
    }
}

#[test]
fn test_drops() {
    DROP_VECTOR.with(|slot| {
        *slot.borrow_mut() = vec![0; 200];
    });

    {
        let mut m = CHashMap::new();

        DROP_VECTOR.with(|v| {
            for i in 0..200 {
                assert_eq!(v.borrow()[i], 0);
            }
        });

        for i in 0..100 {
            let d1 = Dropable::new(i);
            let d2 = Dropable::new(i+100);
            m.insert(d1, d2);
        }

        DROP_VECTOR.with(|v| {
            for i in 0..200 {
                assert_eq!(v.borrow()[i], 1);
            }
        });

        for i in 0..50 {
            let k = Dropable::new(i);
            let v = m.remove(&k);

            assert!(v.is_some());

            DROP_VECTOR.with(|v| {
                assert_eq!(v.borrow()[i], 1);
                assert_eq!(v.borrow()[i+100], 1);
            });
        }

        DROP_VECTOR.with(|v| {
            for i in 0..50 {
                assert_eq!(v.borrow()[i], 0);
                assert_eq!(v.borrow()[i+100], 0);
            }

            for i in 50..100 {
                assert_eq!(v.borrow()[i], 1);
                assert_eq!(v.borrow()[i+100], 1);
            }
        });
    }

    DROP_VECTOR.with(|v| {
        for i in 0..200 {
            assert_eq!(v.borrow()[i], 0);
        }
    });
}

#[test]
fn test_move_iter_drops() {
    DROP_VECTOR.with(|v| {
        *v.borrow_mut() = vec![0; 200];
    });

    let hm = {
        let mut hm = CHashMap::new();

        DROP_VECTOR.with(|v| {
            for i in 0..200 {
                assert_eq!(v.borrow()[i], 0);
            }
        });

        for i in 0..100 {
            let d1 = Dropable::new(i);
            let d2 = Dropable::new(i+100);
            hm.insert(d1, d2);
        }

        DROP_VECTOR.with(|v| {
            for i in 0..200 {
                assert_eq!(v.borrow()[i], 1);
            }
        });

        hm
    };

    // By the way, ensure that cloning doesn't screw up the dropping.
    drop(hm.clone());

    {
        let mut half = hm.into_iter().take(50);

        DROP_VECTOR.with(|v| {
            for i in 0..200 {
                assert_eq!(v.borrow()[i], 1);
            }
        });

        for _ in half.by_ref() {}

        DROP_VECTOR.with(|v| {
            let nk = (0..100).filter(|&i| {
                v.borrow()[i] == 1
            }).count();

            let nv = (0..100).filter(|&i| {
                v.borrow()[i+100] == 1
            }).count();

            assert_eq!(nk, 50);
            assert_eq!(nv, 50);
        });
    };

    DROP_VECTOR.with(|v| {
        for i in 0..200 {
            assert_eq!(v.borrow()[i], 0);
        }
    });
}

#[test]
fn test_empty_pop() {
    let mut m: CHashMap<isize, bool> = CHashMap::new();
    assert_eq!(m.remove(&0), None);
}

#[test]
fn test_lots_of_insertions() {
    let mut m = CHashMap::new();

    // Try this a few times to make sure we never screw up the hashmap's
    // internal state.
    for _ in 0..10 {
        assert!(m.is_empty());

        for i in 1..1001 {
            assert!(m.insert(i, i).is_none());

            for j in 1..i+1 {
                let r = m.get(&j);
                assert_eq!(r, Some(&j));
            }

            for j in i+1..1001 {
                let r = m.get(&j);
                assert_eq!(r, None);
            }
        }

        for i in 1001..2001 {
            assert!(!m.contains_key(&i));
        }

        // remove forwards
        for i in 1..1001 {
            assert!(m.remove(&i).is_some());

            for j in 1..i+1 {
                assert!(!m.contains_key(&j));
            }

            for j in i+1..1001 {
                assert!(m.contains_key(&j));
            }
        }

        for i in 1..1001 {
            assert!(!m.contains_key(&i));
        }

        for i in 1..1001 {
            assert!(m.insert(i, i).is_none());
        }

        // remove backwards
        for i in (1..1001).rev() {
            assert!(m.remove(&i).is_some());

            for j in i..1001 {
                assert!(!m.contains_key(&j));
            }

            for j in 1..i {
                assert!(m.contains_key(&j));
            }
        }
    }
}

#[test]
fn test_find_mut() {
    let mut m = CHashMap::new();
    assert!(m.insert(1, 12).is_none());
    assert!(m.insert(2, 8).is_none());
    assert!(m.insert(5, 14).is_none());
    let new = 100;
    match m.get_mut(&5) {
        None => panic!(), Some(x) => *x = new
    }
    assert_eq!(m.get(&5), Some(&new));
}

#[test]
fn test_insert_overwrite() {
    let mut m = CHashMap::new();
    assert!(m.insert(1, 2).is_none());
    assert_eq!(*m.get(&1).unwrap(), 2);
    assert!(!m.insert(1, 3).is_none());
    assert_eq!(*m.get(&1).unwrap(), 3);
}

#[test]
fn test_insert_conflicts() {
    let mut m = CHashMap::with_capacity(4);
    assert!(m.insert(1, 2).is_none());
    assert!(m.insert(5, 3).is_none());
    assert!(m.insert(9, 4).is_none());
    assert_eq!(*m.get(&9).unwrap(), 4);
    assert_eq!(*m.get(&5).unwrap(), 3);
    assert_eq!(*m.get(&1).unwrap(), 2);
}

#[test]
fn test_conflict_remove() {
    let mut m = CHashMap::with_capacity(4);
    assert!(m.insert(1, 2).is_none());
    assert_eq!(*m.get(&1).unwrap(), 2);
    assert!(m.insert(5, 3).is_none());
    assert_eq!(*m.get(&1).unwrap(), 2);
    assert_eq!(*m.get(&5).unwrap(), 3);
    assert!(m.insert(9, 4).is_none());
    assert_eq!(*m.get(&1).unwrap(), 2);
    assert_eq!(*m.get(&5).unwrap(), 3);
    assert_eq!(*m.get(&9).unwrap(), 4);
    assert!(m.remove(&1).is_some());
    assert_eq!(*m.get(&9).unwrap(), 4);
    assert_eq!(*m.get(&5).unwrap(), 3);
}

#[test]
fn test_is_empty() {
    let mut m = CHashMap::with_capacity(4);
    assert!(m.insert(1, 2).is_none());
    assert!(!m.is_empty());
    assert!(m.remove(&1).is_some());
    assert!(m.is_empty());
}

#[test]
fn test_pop() {
    let mut m = CHashMap::new();
    m.insert(1, 2);
    assert_eq!(m.remove(&1), Some(2));
    assert_eq!(m.remove(&1), None);
}

#[test]
fn test_keys() {
    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
    let map: CHashMap<_, _> = vec.into_iter().collect();
    let keys: Vec<_> = map.keys().cloned().collect();
    assert_eq!(keys.len(), 3);
    assert!(keys.contains(&1));
    assert!(keys.contains(&2));
    assert!(keys.contains(&3));
}

#[test]
fn test_values() {
    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
    let map: CHashMap<_, _> = vec.into_iter().collect();
    let values: Vec<_> = map.values().cloned().collect();
    assert_eq!(values.len(), 3);
    assert!(values.contains(&'a'));
    assert!(values.contains(&'b'));
    assert!(values.contains(&'c'));
}

#[test]
fn test_find() {
    let mut m = CHashMap::new();
    assert!(m.get(&1).is_none());
    m.insert(1, 2);
    match m.get(&1) {
        None => panic!(),
        Some(v) => assert_eq!(*v, 2)
    }
}

#[test]
fn test_expand() {
    let mut m = CHashMap::new();

    assert_eq!(m.len(), 0);
    assert!(m.is_empty());

    let mut i = 0;
    let old_cap = m.table.capacity();
    while old_cap == m.table.capacity() {
        m.insert(i, i);
        i += 1;
    }

    assert_eq!(m.len(), i);
    assert!(!m.is_empty());
}

#[test]
fn test_behavior_resize_policy() {
    let mut m = CHashMap::new();

    assert_eq!(m.len(), 0);
    assert_eq!(m.table.capacity(), 0);
    assert!(m.is_empty());

    m.insert(0, 0);
    m.remove(&0);
    assert!(m.is_empty());
    let initial_cap = m.table.capacity();
    m.reserve(initial_cap);
    let cap = m.table.capacity();

    assert_eq!(cap, initial_cap * 2);

    let mut i = 0;
    for _ in 0..cap * 3 / 4 {
        m.insert(i, i);
        i += 1;
    }
    // three quarters full

    assert_eq!(m.len(), i);
    assert_eq!(m.table.capacity(), cap);

    for _ in 0..cap / 4 {
        m.insert(i, i);
        i += 1;
    }
    // half full

    let new_cap = m.table.capacity();
    assert_eq!(new_cap, cap * 2);

    for _ in 0..cap / 2 - 1 {
        i -= 1;
        m.remove(&i);
        assert_eq!(m.table.capacity(), new_cap);
    }
    // A little more than one quarter full.
    m.shrink_to_fit();
    assert_eq!(m.table.capacity(), cap);
    // again, a little more than half full
    for _ in 0..cap / 2 - 1 {
        i -= 1;
        m.remove(&i);
    }
    m.shrink_to_fit();

    assert_eq!(m.len(), i);
    assert!(!m.is_empty());
    assert_eq!(m.table.capacity(), initial_cap);
}

#[test]
fn test_reserve_shrink_to_fit() {
    let mut m = CHashMap::new();
    m.insert(0, 0);
    m.remove(&0);
    assert!(m.capacity() >= m.len());
    for i in 0..128 {
        m.insert(i, i);
    }
    m.reserve(256);

    let usable_cap = m.capacity();
    for i in 128..(128 + 256) {
        m.insert(i, i);
        assert_eq!(m.capacity(), usable_cap);
    }

    for i in 100..(128 + 256) {
        assert_eq!(m.remove(&i), Some(i));
    }
    m.shrink_to_fit();

    assert_eq!(m.len(), 100);
    assert!(!m.is_empty());
    assert!(m.capacity() >= m.len());

    for i in 0..100 {
        assert_eq!(m.remove(&i), Some(i));
    }
    m.shrink_to_fit();
    m.insert(0, 0);

    assert_eq!(m.len(), 1);
    assert!(m.capacity() >= m.len());
    assert_eq!(m.remove(&0), Some(0));
}

#[test]
fn test_from_iter() {
    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];

    let map: CHashMap<_, _> = xs.iter().cloned().collect();

    for &(k, v) in &xs {
        assert_eq!(map.get(&k), Some(&v));
    }
}

#[test]
fn test_size_hint() {
    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];

    let map: CHashMap<_, _>  = xs.iter().cloned().collect();

    let mut iter = map.iter();

    for _ in iter.by_ref().take(3) {}

    assert_eq!(iter.size_hint(), (3, Some(3)));
}

#[test]
fn test_iter_len() {
    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];

    let map: CHashMap<_, _>  = xs.iter().cloned().collect();

    let mut iter = map.iter();

    for _ in iter.by_ref().take(3) {}

    assert_eq!(iter.len(), 3);
}

#[test]
fn test_mut_size_hint() {
    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];

    let mut map: CHashMap<_, _>  = xs.iter().cloned().collect();

    let mut iter = map.iter_mut();

    for _ in iter.by_ref().take(3) {}

    assert_eq!(iter.size_hint(), (3, Some(3)));
}

#[test]
fn test_iter_mut_len() {
    let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];

    let mut map: CHashMap<_, _>  = xs.iter().cloned().collect();

    let mut iter = map.iter_mut();

    for _ in iter.by_ref().take(3) {}

    assert_eq!(iter.len(), 3);
}

#[test]
fn test_capacity_not_less_than_len() {
    let mut a = CHashMap::new();
    let mut item = 0;

    for _ in 0..116 {
        a.insert(item, 0);
        item += 1;
    }

    assert!(a.capacity() > a.len());

    let free = a.capacity() - a.len();
    for _ in 0..free {
        a.insert(item, 0);
        item += 1;
    }

    assert_eq!(a.len(), a.capacity());

    // Insert at capacity should cause allocation.
    a.insert(item, 0);
    assert!(a.capacity() > a.len());
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate time;

use self::hyper::Client;
use self::hyper::header::Connection;
use self::time::*;

pub struct Request {
    pub elapsed_time: f64
}

impl Request{
    pub fn new(elapsed_time: f64) -> Request {
        Request {
            elapsed_time: elapsed_time,
        }
    }

    pub fn create_request(host: &str) -> f64 {
        let mut client = Client::new();
        let start = time::precise_time_s();

        let _res = client.get(host)
            .header(Connection::close())
            .send().unwrap();

        let end = time::precise_time_s();

        return end-start;
    }

    pub fn total_requests_made(requests: &mut Vec<Request>) -> i32 {
        return requests.len() as i32;
    }

    pub fn calculate_mean(requests: &mut Vec<Request>) -> f64 {
        let mut total_duration = 0.0;
        let total_requests = requests.len() as f64;

        for r in requests.iter() {
            total_duration = total_duration + r.elapsed_time;
        }

        return total_duration/total_requests as f64;
    }
}

#[cfg(test)]
mod test {
    use super::Request;

    #[test]
    fn test_total_requests_made_returns_expected_integer() {
        let mut requests = &mut Vec::new();

        for x in 0..5 {
            requests.push(Request::new(0.56));
        }

        assert_eq!(5, Request::total_requests_made(requests));
    }

    #[test]
    fn test_calculate_mean_returns_expected_integer() {
        let mut requests = &mut Vec::new();

        requests.push(Request::new(0.56));
        requests.push(Request::new(0.76));

        assert_eq!(0.66, Request::calculate_mean(requests));
    }
}<commit_msg>add error handling so that we don't panic! upon unwrap()'ing an Err<commit_after>extern crate hyper;
extern crate time;

use self::hyper::Client;
use self::hyper::header::Connection;
use self::time::*;

pub struct Request {
    pub elapsed_time: f64
}

impl Request{
    pub fn new(elapsed_time: f64) -> Request {
        Request {
            elapsed_time: elapsed_time,
        }
    }

    pub fn create_request(host: &str) -> f64 {
        let mut client = Client::new();
        let start = time::precise_time_s();

        let _res = client.get(host)
            .header(Connection::close())
            .send();

        if let Err(res) = _res {
            println!("Err: {:?}", res);
        } else {
            _res.unwrap();
        }

        let end = time::precise_time_s();

        return end-start;
    }

    pub fn total_requests_made(requests: &mut Vec<Request>) -> i32 {
        return requests.len() as i32;
    }

    pub fn calculate_mean(requests: &mut Vec<Request>) -> f64 {
        let mut total_duration = 0.0;
        let total_requests = requests.len() as f64;

        for r in requests.iter() {
            total_duration = total_duration + r.elapsed_time;
        }

        return total_duration/total_requests as f64;
    }
}

#[cfg(test)]
mod test {
    use super::Request;

    #[test]
    fn test_total_requests_made_returns_expected_integer() {
        let mut requests = &mut Vec::new();

        for x in 0..5 {
            requests.push(Request::new(0.56));
        }

        assert_eq!(5, Request::total_requests_made(requests));
    }

    #[test]
    fn test_calculate_mean_returns_expected_integer() {
        let mut requests = &mut Vec::new();

        requests.push(Request::new(0.56));
        requests.push(Request::new(0.76));

        assert_eq!(0.66, Request::calculate_mean(requests));
    }
}
<|endoftext|>


<commit_before><commit_msg>coap work<commit_after><|endoftext|>


<commit_before><commit_msg>Don't offset pointers at the deleted chunk<commit_after><|endoftext|>


<commit_before>use context::{mod, GlVersion};
use gl;
use libc;
use std::c_vec::CVec;
use std::{fmt, mem, ptr};
use std::sync::Arc;
use GlObject;

/// A buffer in the graphics card's memory.
pub struct Buffer {
    display: Arc<super::DisplayImpl>,
    id: gl::types::GLuint,
    elements_size: uint,
    elements_count: uint,
}

/// Type of a buffer.
pub trait BufferType {
    /// Should return `&mut state.something`.
    fn get_storage_point(Option<Self>, &mut context::GLState)
        -> &mut Option<gl::types::GLuint>;
    /// Should return `gl::SOMETHING_BUFFER`.
    fn get_bind_point(Option<Self>) -> gl::types::GLenum;
}

/// Used for vertex buffers.
pub struct ArrayBuffer;

impl BufferType for ArrayBuffer {
    fn get_storage_point(_: Option<ArrayBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.array_buffer_binding
    }

    fn get_bind_point(_: Option<ArrayBuffer>) -> gl::types::GLenum {
        gl::ARRAY_BUFFER
    }
}

/// Used for index buffers.
pub struct ElementArrayBuffer;

impl BufferType for ElementArrayBuffer {
    fn get_storage_point(_: Option<ElementArrayBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.element_array_buffer_binding
    }

    fn get_bind_point(_: Option<ElementArrayBuffer>) -> gl::types::GLenum {
        gl::ELEMENT_ARRAY_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelPackBuffer;

impl BufferType for PixelPackBuffer {
    fn get_storage_point(_: Option<PixelPackBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.pixel_pack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelPackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_PACK_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelUnpackBuffer;

impl BufferType for PixelUnpackBuffer {
    fn get_storage_point(_: Option<PixelUnpackBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.pixel_unpack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelUnpackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_UNPACK_BUFFER
    }
}

impl Buffer {
    pub fn new<T, D>(display: &super::Display, data: Vec<D>, usage: gl::types::GLenum)
        -> Buffer where T: BufferType, D: Send + Copy
    {
        use std::mem;

        let elements_size = {
            let d0: *const D = &data[0];
            let d1: *const D = &data[1];
            (d1 as uint) - (d0 as uint)
        };

        let elements_count = data.len();
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();

        display.context.context.exec(proc(gl, state, version, extensions) {
            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                gl.GenBuffers(1, &mut id);

                if version >= &GlVersion(4, 5) {
                    gl.NamedBufferData(id, buffer_size as gl::types::GLsizei,
                        data.as_ptr() as *const libc::c_void, usage);

                } else if extensions.gl_ext_direct_state_access {
                    gl.NamedBufferDataEXT(id, buffer_size as gl::types::GLsizeiptr,
                        data.as_ptr() as *const libc::c_void, usage);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr,
                        data.as_ptr() as *const libc::c_void, usage);
                }

                tx.send(id);
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn new_empty<T>(display: &super::Display, elements_size: uint, elements_count: uint,
                        usage: gl::types::GLenum) -> Buffer where T: BufferType
    {
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();
        display.context.context.exec(proc(gl, state, version, extensions) {
            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                gl.GenBuffers(1, &mut id);

                if version >= &GlVersion(4, 5) {
                    gl.NamedBufferData(id, buffer_size as gl::types::GLsizei, ptr::null(), usage);

                } else if extensions.gl_ext_direct_state_access {
                    gl.NamedBufferDataEXT(id, buffer_size as gl::types::GLsizeiptr, ptr::null(),
                        usage);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr, ptr::null(), usage);
                }

                tx.send(id);
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn get_display(&self) -> &Arc<super::DisplayImpl> {
        &self.display
    }

    pub fn get_elements_size(&self) -> uint {
        self.elements_size
    }

    pub fn get_elements_count(&self) -> uint {
        self.elements_count
    }

    pub fn get_total_size(&self) -> uint {
        self.elements_count * self.elements_size
    }

    pub fn map<'a, T, D>(&'a mut self) -> Mapping<'a, T, D> where T: BufferType, D: Send {
        let (tx, rx) = channel();
        let id = self.id.clone();
        let elements_count = self.elements_count.clone();

        self.display.context.exec(proc(gl, state, version, _) {
            let ptr = unsafe {
                if version >= &GlVersion(4, 5) {
                    gl.MapNamedBuffer(id, gl::READ_WRITE)

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.MapBuffer(bind, gl::READ_WRITE)
                }
            };

            if ptr.is_null() {
                tx.send(Err("glMapBuffer returned null"));
            } else {
                tx.send(Ok(ptr as *mut D));
            }
        });

        Mapping {
            buffer: self,
            data: unsafe { CVec::new(rx.recv().unwrap(), elements_count) },
        }
    }

    pub fn read<T, D>(&self) -> Vec<D> where T: BufferType, D: Send {
        self.read_slice::<T, D>(0, self.elements_count)
    }

    pub fn read_slice<T, D>(&self, offset: uint, size: uint)
                            -> Vec<D> where T: BufferType, D: Send
    {
        assert!(offset + size <= self.elements_count);

        let id = self.id.clone();
        let elements_size = self.elements_size.clone();
        let (tx, rx) = channel();

        self.display.context.exec(proc(gl, state, version, _) {
            unsafe {
                let mut data = Vec::with_capacity(size);
                data.set_len(size);

                if version >= &GlVersion(4, 5) {
                    gl.GetNamedBufferSubData(id, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizei,
                        data.as_mut_ptr() as *mut libc::c_void);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.GetBufferSubData(bind, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizeiptr,
                        data.as_mut_ptr() as *mut libc::c_void);
                }

                tx.send_opt(data).ok();
            }
        });

        rx.recv()
    }
}

impl fmt::Show for Buffer {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        (format!("Buffer #{}", self.id)).fmt(formatter)
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        let id = self.id.clone();
        self.display.context.exec(proc(gl, state, _, _) {
            if state.array_buffer_binding == Some(id) {
                state.array_buffer_binding = None;
            }

            if state.element_array_buffer_binding == Some(id) {
                state.element_array_buffer_binding = None;
            }

            if state.pixel_pack_buffer_binding == Some(id) {
                state.pixel_pack_buffer_binding = None;
            }

            if state.pixel_unpack_buffer_binding == Some(id) {
                state.pixel_unpack_buffer_binding = None;
            }

            unsafe { gl.DeleteBuffers(1, [ id ].as_ptr()); }
        });
    }
}

impl GlObject for Buffer {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

/// Describes the attribute of a vertex.
///
/// When you create a vertex buffer, you need to pass some sort of array of data. In order for
/// OpenGL to use this data, we must tell it some informations about each field of each
/// element. This structure describes one such field.
#[deriving(Show, Clone)]
pub struct VertexAttrib {
    /// The offset, in bytes, between the start of each vertex and the attribute.
    pub offset: uint,

    /// Type of the field.
    pub data_type: gl::types::GLenum,

    /// Number of invidual elements in the attribute.
    ///
    /// For example if `data_type` is a f32 and `elements_count` is 2, then you have a `vec2`.
    pub elements_count: u32,
}

/// Describes the layout of each vertex in a vertex buffer.
pub type VertexBindings = Vec<(String, VertexAttrib)>;

/// Trait for structures that represent a vertex.
pub trait VertexFormat: Copy {
    /// Builds the `VertexBindings` representing the layout of this element.
    fn build_bindings(Option<Self>) -> VertexBindings;
}

/// A mapping of a buffer.
pub struct Mapping<'b, T, D> {
    buffer: &'b mut Buffer,
    data: CVec<D>,
}

#[unsafe_destructor]
impl<'a, T, D> Drop for Mapping<'a, T, D> where T: BufferType {
    fn drop(&mut self) {
        let id = self.buffer.id.clone();
        self.buffer.display.context.exec(proc(gl, state, version, _) {
            unsafe {
                if version >= &GlVersion(4, 5) {
                    gl.UnmapNamedBuffer(id);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    if *storage != Some(id) {
                        gl.BindBuffer(bind, id);
                        *storage = Some(id);
                    }

                    gl.UnmapBuffer(bind);
                }
            }
        });
    }
}

impl<'a, T, D> Deref<[D]> for Mapping<'a, T, D> {
    fn deref<'b>(&'b self) -> &'b [D] {
        self.data.as_slice()
    }
}

impl<'a, T, D> DerefMut<[D]> for Mapping<'a, T, D> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut [D] {
        self.data.as_mut_slice()
    }
}
<commit_msg>Minor optimization when creating a buffer<commit_after>use context::{mod, GlVersion};
use gl;
use libc;
use std::c_vec::CVec;
use std::{fmt, mem, ptr};
use std::sync::Arc;
use GlObject;

/// A buffer in the graphics card's memory.
pub struct Buffer {
    display: Arc<super::DisplayImpl>,
    id: gl::types::GLuint,
    elements_size: uint,
    elements_count: uint,
}

/// Type of a buffer.
pub trait BufferType {
    /// Should return `&mut state.something`.
    fn get_storage_point(Option<Self>, &mut context::GLState)
        -> &mut Option<gl::types::GLuint>;
    /// Should return `gl::SOMETHING_BUFFER`.
    fn get_bind_point(Option<Self>) -> gl::types::GLenum;
}

/// Used for vertex buffers.
pub struct ArrayBuffer;

impl BufferType for ArrayBuffer {
    fn get_storage_point(_: Option<ArrayBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.array_buffer_binding
    }

    fn get_bind_point(_: Option<ArrayBuffer>) -> gl::types::GLenum {
        gl::ARRAY_BUFFER
    }
}

/// Used for index buffers.
pub struct ElementArrayBuffer;

impl BufferType for ElementArrayBuffer {
    fn get_storage_point(_: Option<ElementArrayBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.element_array_buffer_binding
    }

    fn get_bind_point(_: Option<ElementArrayBuffer>) -> gl::types::GLenum {
        gl::ELEMENT_ARRAY_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelPackBuffer;

impl BufferType for PixelPackBuffer {
    fn get_storage_point(_: Option<PixelPackBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.pixel_pack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelPackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_PACK_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelUnpackBuffer;

impl BufferType for PixelUnpackBuffer {
    fn get_storage_point(_: Option<PixelUnpackBuffer>, state: &mut context::GLState)
        -> &mut Option<gl::types::GLuint>
    {
        &mut state.pixel_unpack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelUnpackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_UNPACK_BUFFER
    }
}

impl Buffer {
    pub fn new<T, D>(display: &super::Display, data: Vec<D>, usage: gl::types::GLenum)
        -> Buffer where T: BufferType, D: Send + Copy
    {
        use std::mem;

        let elements_size = {
            let d0: *const D = &data[0];
            let d1: *const D = &data[1];
            (d1 as uint) - (d0 as uint)
        };

        let elements_count = data.len();
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();

        display.context.context.exec(proc(gl, state, version, extensions) {
            let data = data;

            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                gl.GenBuffers(1, &mut id);
                tx.send(id);

                if version >= &GlVersion(4, 5) {
                    gl.NamedBufferData(id, buffer_size as gl::types::GLsizei,
                        data.as_ptr() as *const libc::c_void, usage);

                } else if extensions.gl_ext_direct_state_access {
                    gl.NamedBufferDataEXT(id, buffer_size as gl::types::GLsizeiptr,
                        data.as_ptr() as *const libc::c_void, usage);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr,
                        data.as_ptr() as *const libc::c_void, usage);
                }
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn new_empty<T>(display: &super::Display, elements_size: uint, elements_count: uint,
                        usage: gl::types::GLenum) -> Buffer where T: BufferType
    {
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();
        display.context.context.exec(proc(gl, state, version, extensions) {
            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                gl.GenBuffers(1, &mut id);

                if version >= &GlVersion(4, 5) {
                    gl.NamedBufferData(id, buffer_size as gl::types::GLsizei, ptr::null(), usage);

                } else if extensions.gl_ext_direct_state_access {
                    gl.NamedBufferDataEXT(id, buffer_size as gl::types::GLsizeiptr, ptr::null(),
                        usage);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr, ptr::null(), usage);
                }

                tx.send(id);
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn get_display(&self) -> &Arc<super::DisplayImpl> {
        &self.display
    }

    pub fn get_elements_size(&self) -> uint {
        self.elements_size
    }

    pub fn get_elements_count(&self) -> uint {
        self.elements_count
    }

    pub fn get_total_size(&self) -> uint {
        self.elements_count * self.elements_size
    }

    pub fn map<'a, T, D>(&'a mut self) -> Mapping<'a, T, D> where T: BufferType, D: Send {
        let (tx, rx) = channel();
        let id = self.id.clone();
        let elements_count = self.elements_count.clone();

        self.display.context.exec(proc(gl, state, version, _) {
            let ptr = unsafe {
                if version >= &GlVersion(4, 5) {
                    gl.MapNamedBuffer(id, gl::READ_WRITE)

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.MapBuffer(bind, gl::READ_WRITE)
                }
            };

            if ptr.is_null() {
                tx.send(Err("glMapBuffer returned null"));
            } else {
                tx.send(Ok(ptr as *mut D));
            }
        });

        Mapping {
            buffer: self,
            data: unsafe { CVec::new(rx.recv().unwrap(), elements_count) },
        }
    }

    pub fn read<T, D>(&self) -> Vec<D> where T: BufferType, D: Send {
        self.read_slice::<T, D>(0, self.elements_count)
    }

    pub fn read_slice<T, D>(&self, offset: uint, size: uint)
                            -> Vec<D> where T: BufferType, D: Send
    {
        assert!(offset + size <= self.elements_count);

        let id = self.id.clone();
        let elements_size = self.elements_size.clone();
        let (tx, rx) = channel();

        self.display.context.exec(proc(gl, state, version, _) {
            unsafe {
                let mut data = Vec::with_capacity(size);
                data.set_len(size);

                if version >= &GlVersion(4, 5) {
                    gl.GetNamedBufferSubData(id, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizei,
                        data.as_mut_ptr() as *mut libc::c_void);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    gl.BindBuffer(bind, id);
                    *storage = Some(id);
                    gl.GetBufferSubData(bind, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizeiptr,
                        data.as_mut_ptr() as *mut libc::c_void);
                }

                tx.send_opt(data).ok();
            }
        });

        rx.recv()
    }
}

impl fmt::Show for Buffer {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::FormatError> {
        (format!("Buffer #{}", self.id)).fmt(formatter)
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        let id = self.id.clone();
        self.display.context.exec(proc(gl, state, _, _) {
            if state.array_buffer_binding == Some(id) {
                state.array_buffer_binding = None;
            }

            if state.element_array_buffer_binding == Some(id) {
                state.element_array_buffer_binding = None;
            }

            if state.pixel_pack_buffer_binding == Some(id) {
                state.pixel_pack_buffer_binding = None;
            }

            if state.pixel_unpack_buffer_binding == Some(id) {
                state.pixel_unpack_buffer_binding = None;
            }

            unsafe { gl.DeleteBuffers(1, [ id ].as_ptr()); }
        });
    }
}

impl GlObject for Buffer {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

/// Describes the attribute of a vertex.
///
/// When you create a vertex buffer, you need to pass some sort of array of data. In order for
/// OpenGL to use this data, we must tell it some informations about each field of each
/// element. This structure describes one such field.
#[deriving(Show, Clone)]
pub struct VertexAttrib {
    /// The offset, in bytes, between the start of each vertex and the attribute.
    pub offset: uint,

    /// Type of the field.
    pub data_type: gl::types::GLenum,

    /// Number of invidual elements in the attribute.
    ///
    /// For example if `data_type` is a f32 and `elements_count` is 2, then you have a `vec2`.
    pub elements_count: u32,
}

/// Describes the layout of each vertex in a vertex buffer.
pub type VertexBindings = Vec<(String, VertexAttrib)>;

/// Trait for structures that represent a vertex.
pub trait VertexFormat: Copy {
    /// Builds the `VertexBindings` representing the layout of this element.
    fn build_bindings(Option<Self>) -> VertexBindings;
}

/// A mapping of a buffer.
pub struct Mapping<'b, T, D> {
    buffer: &'b mut Buffer,
    data: CVec<D>,
}

#[unsafe_destructor]
impl<'a, T, D> Drop for Mapping<'a, T, D> where T: BufferType {
    fn drop(&mut self) {
        let id = self.buffer.id.clone();
        self.buffer.display.context.exec(proc(gl, state, version, _) {
            unsafe {
                if version >= &GlVersion(4, 5) {
                    gl.UnmapNamedBuffer(id);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    if *storage != Some(id) {
                        gl.BindBuffer(bind, id);
                        *storage = Some(id);
                    }

                    gl.UnmapBuffer(bind);
                }
            }
        });
    }
}

impl<'a, T, D> Deref<[D]> for Mapping<'a, T, D> {
    fn deref<'b>(&'b self) -> &'b [D] {
        self.data.as_slice()
    }
}

impl<'a, T, D> DerefMut<[D]> for Mapping<'a, T, D> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut [D] {
        self.data.as_mut_slice()
    }
}
<|endoftext|>


<commit_before>//! Matrix user identifiers.

use std::{
    convert::TryFrom,
    fmt::{Display, Formatter, Result as FmtResult},
};

#[cfg(feature = "diesel")]
use diesel::sql_types::Text;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use url::Host;

use crate::{deserialize_id, display, error::Error, generate_localpart, parse_id};

/// A Matrix user ID.
///
/// A `UserId` is generated randomly or converted from a string slice, and can be converted back
/// into a string as needed.
///
/// ```
/// # use std::convert::TryFrom;
/// # use ruma_identifiers::UserId;
/// assert_eq!(
///     UserId::try_from("@carl:example.com").unwrap().to_string(),
///     "@carl:example.com"
/// );
/// ```
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "diesel", derive(FromSqlRow, QueryId, AsExpression, SqlType))]
#[cfg_attr(feature = "diesel", sql_type = "Text")]
pub struct UserId {
    /// The hostname of the homeserver.
    hostname: Host,
    /// The user's unique ID.
    localpart: String,
    /// The network port of the homeserver.
    port: u16,
}

impl UserId {
    /// Attempts to generate a `UserId` for the given origin server with a localpart consisting of
    /// 12 random ASCII characters.
    ///
    /// Fails if the given homeserver cannot be parsed as a valid host.
    pub fn new(homeserver_host: &str) -> Result<Self, Error> {
        let user_id = format!(
            "@{}:{}",
            generate_localpart(12).to_lowercase(),
            homeserver_host
        );
        let (localpart, host, port) = parse_id('@', &user_id)?;

        Ok(Self {
            hostname: host,
            localpart: localpart.to_string(),
            port,
        })
    }

    /// Returns a `Host` for the user ID, containing the server name (minus the port) of the
    /// originating homeserver.
    ///
    /// The host can be either a domain name, an IPv4 address, or an IPv6 address.
    pub fn hostname(&self) -> &Host {
        &self.hostname
    }

    /// Returns the user's localpart.
    pub fn localpart(&self) -> &str {
        &self.localpart
    }

    /// Returns the port the originating homeserver can be accessed on.
    pub fn port(&self) -> u16 {
        self.port
    }
}

impl Display for UserId {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        display(f, '@', &self.localpart, &self.hostname, self.port)
    }
}

impl Serialize for UserId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de> Deserialize<'de> for UserId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserialize_id(deserializer, "a Matrix user ID as a string")
    }
}

impl<'a> TryFrom<&'a str> for UserId {
    type Error = Error;

    /// Attempts to create a new Matrix user ID from a string representation.
    ///
    /// The string must include the leading @ sigil, the localpart, a literal colon, and a valid
    /// server name.
    fn try_from(user_id: &'a str) -> Result<Self, Error> {
        let (localpart, host, port) = parse_id('@', user_id)?;
        let downcased_localpart = localpart.to_lowercase();

        // See https://matrix.org/docs/spec/appendices#user-identifiers
        if downcased_localpart.bytes().any(|b| match b {
            b'0'..=b'9' | b'a'..=b'z' | b'-' | b'.' | b'=' | b'_' | b'/' => false,
            _ => true,
        }) {
            return Err(Error::InvalidCharacters);
        }

        Ok(Self {
            hostname: host,
            port,
            localpart: downcased_localpart,
        })
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    use serde_json::{from_str, to_string};

    use super::UserId;
    use crate::error::Error;

    #[test]
    fn valid_user_id() {
        assert_eq!(
            UserId::try_from("@carl:example.com")
                .expect("Failed to create UserId.")
                .to_string(),
            "@carl:example.com"
        );
    }

    #[test]
    fn downcase_user_id() {
        assert_eq!(
            UserId::try_from("@CARL:example.com")
                .expect("Failed to create UserId.")
                .to_string(),
            "@carl:example.com"
        );
    }

    #[test]
    fn generate_random_valid_user_id() {
        let user_id = UserId::new("example.com")
            .expect("Failed to generate UserId.")
            .to_string();

        assert!(user_id.to_string().starts_with('@'));
        assert_eq!(user_id.len(), 25);
    }

    #[test]
    fn generate_random_invalid_user_id() {
        assert!(UserId::new("").is_err());
    }

    #[test]
    fn serialize_valid_user_id() {
        assert_eq!(
            to_string(&UserId::try_from("@carl:example.com").expect("Failed to create UserId."))
                .expect("Failed to convert UserId to JSON."),
            r#""@carl:example.com""#
        );
    }

    #[test]
    fn deserialize_valid_user_id() {
        assert_eq!(
            from_str::<UserId>(r#""@carl:example.com""#).expect("Failed to convert JSON to UserId"),
            UserId::try_from("@carl:example.com").expect("Failed to create UserId.")
        );
    }

    #[test]
    fn valid_user_id_with_explicit_standard_port() {
        assert_eq!(
            UserId::try_from("@carl:example.com:443")
                .expect("Failed to create UserId.")
                .to_string(),
            "@carl:example.com"
        );
    }

    #[test]
    fn valid_user_id_with_non_standard_port() {
        assert_eq!(
            UserId::try_from("@carl:example.com:5000")
                .expect("Failed to create UserId.")
                .to_string(),
            "@carl:example.com:5000"
        );
    }

    #[test]
    fn invalid_characters_in_user_id_localpart() {
        assert_eq!(
            UserId::try_from("@%%%:example.com").err().unwrap(),
            Error::InvalidCharacters
        );
    }

    #[test]
    fn missing_user_id_sigil() {
        assert_eq!(
            UserId::try_from("carl:example.com").err().unwrap(),
            Error::MissingSigil
        );
    }

    #[test]
    fn missing_user_id_delimiter() {
        assert_eq!(
            UserId::try_from("@carl").err().unwrap(),
            Error::MissingDelimiter
        );
    }

    #[test]
    fn invalid_user_id_host() {
        assert_eq!(
            UserId::try_from("@carl:/").err().unwrap(),
            Error::InvalidHost
        );
    }

    #[test]
    fn invalid_user_id_port() {
        assert_eq!(
            UserId::try_from("@carl:example.com:notaport")
                .err()
                .unwrap(),
            Error::InvalidHost
        );
    }
}
<commit_msg>Support historical user IDs<commit_after>//! Matrix user identifiers.

use std::{
    convert::TryFrom,
    fmt::{Display, Formatter, Result as FmtResult},
};

#[cfg(feature = "diesel")]
use diesel::sql_types::Text;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use url::Host;

use crate::{deserialize_id, display, error::Error, generate_localpart, parse_id};

/// A Matrix user ID.
///
/// A `UserId` is generated randomly or converted from a string slice, and can be converted back
/// into a string as needed.
///
/// ```
/// # use std::convert::TryFrom;
/// # use ruma_identifiers::UserId;
/// assert_eq!(
///     UserId::try_from("@carl:example.com").unwrap().to_string(),
///     "@carl:example.com"
/// );
/// ```
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "diesel", derive(FromSqlRow, QueryId, AsExpression, SqlType))]
#[cfg_attr(feature = "diesel", sql_type = "Text")]
pub struct UserId {
    /// The hostname of the homeserver.
    hostname: Host,
    /// The user's unique ID.
    localpart: String,
    /// The network port of the homeserver.
    port: u16,
    /// Whether this user id is a historical one.
    ///
    /// A historical user id is one that is not legal per the regular user id rules, but was
    /// accepted by previous versions of the spec and thus has to be supported because users with
    /// these kinds of ids still exist.
    is_historical: bool,
}

impl UserId {
    /// Attempts to generate a `UserId` for the given origin server with a localpart consisting of
    /// 12 random ASCII characters.
    ///
    /// Fails if the given homeserver cannot be parsed as a valid host.
    pub fn new(homeserver_host: &str) -> Result<Self, Error> {
        let user_id = format!(
            "@{}:{}",
            generate_localpart(12).to_lowercase(),
            homeserver_host
        );
        let (localpart, host, port) = parse_id('@', &user_id)?;

        Ok(Self {
            hostname: host,
            localpart: localpart.to_string(),
            port,
            is_historical: false,
        })
    }

    /// Returns a `Host` for the user ID, containing the server name (minus the port) of the
    /// originating homeserver.
    ///
    /// The host can be either a domain name, an IPv4 address, or an IPv6 address.
    pub fn hostname(&self) -> &Host {
        &self.hostname
    }

    /// Returns the user's localpart.
    pub fn localpart(&self) -> &str {
        &self.localpart
    }

    /// Returns the port the originating homeserver can be accessed on.
    pub fn port(&self) -> u16 {
        self.port
    }

    /// Whether this user ID is a historical one, i.e. one that doesn't conform to the latest
    /// specification of the user ID grammar but is still accepted because it was previously
    /// allowed.
    pub fn is_historical(&self) -> bool {
        self.is_historical
    }
}

impl Display for UserId {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        display(f, '@', &self.localpart, &self.hostname, self.port)
    }
}

impl Serialize for UserId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de> Deserialize<'de> for UserId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserialize_id(deserializer, "a Matrix user ID as a string")
    }
}

impl<'a> TryFrom<&'a str> for UserId {
    type Error = Error;

    /// Attempts to create a new Matrix user ID from a string representation.
    ///
    /// The string must include the leading @ sigil, the localpart, a literal colon, and a valid
    /// server name.
    fn try_from(user_id: &'a str) -> Result<Self, Error> {
        let (localpart, host, port) = parse_id('@', user_id)?;
        let downcased_localpart = localpart.to_lowercase();

        // See https://matrix.org/docs/spec/appendices#user-identifiers
        let is_fully_conforming = downcased_localpart.bytes().all(|b| match b {
            b'0'..=b'9' | b'a'..=b'z' | b'-' | b'.' | b'=' | b'_' | b'/' => true,
            _ => false,
        });

        // If it's not fully conforming, check if it contains characters that are also disallowed
        // for historical user IDs. If there are, return an error.
        // See https://matrix.org/docs/spec/appendices#historical-user-ids
        if !is_fully_conforming
            && downcased_localpart
                .bytes()
                .any(|b| b < 0x21 || b == b':' || b > 0x7E)
        {
            return Err(Error::InvalidCharacters);
        }

        Ok(Self {
            hostname: host,
            port,
            localpart: downcased_localpart,
            is_historical: !is_fully_conforming,
        })
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    use serde_json::{from_str, to_string};

    use super::UserId;
    use crate::error::Error;

    #[test]
    fn valid_user_id() {
        let user_id = UserId::try_from("@carl:example.com").expect("Failed to create UserId.");
        assert_eq!(user_id.to_string(), "@carl:example.com");
        assert!(!user_id.is_historical());
    }

    #[test]
    fn valid_historical_user_id() {
        let user_id = UserId::try_from("@a%b[irc]:example.com").expect("Failed to create UserId.");
        assert_eq!(user_id.to_string(), "@a%b[irc]:example.com");
        assert!(user_id.is_historical());
    }

    #[test]
    fn downcase_user_id() {
        assert_eq!(
            UserId::try_from("@CARL:example.com")
                .expect("Failed to create UserId.")
                .to_string(),
            "@carl:example.com"
        );
    }

    #[test]
    fn generate_random_valid_user_id() {
        let user_id = UserId::new("example.com")
            .expect("Failed to generate UserId.")
            .to_string();

        assert!(user_id.to_string().starts_with('@'));
        assert_eq!(user_id.len(), 25);
    }

    #[test]
    fn generate_random_invalid_user_id() {
        assert!(UserId::new("").is_err());
    }

    #[test]
    fn serialize_valid_user_id() {
        assert_eq!(
            to_string(&UserId::try_from("@carl:example.com").expect("Failed to create UserId."))
                .expect("Failed to convert UserId to JSON."),
            r#""@carl:example.com""#
        );
    }

    #[test]
    fn deserialize_valid_user_id() {
        assert_eq!(
            from_str::<UserId>(r#""@carl:example.com""#).expect("Failed to convert JSON to UserId"),
            UserId::try_from("@carl:example.com").expect("Failed to create UserId.")
        );
    }

    #[test]
    fn valid_user_id_with_explicit_standard_port() {
        assert_eq!(
            UserId::try_from("@carl:example.com:443")
                .expect("Failed to create UserId.")
                .to_string(),
            "@carl:example.com"
        );
    }

    #[test]
    fn valid_user_id_with_non_standard_port() {
        let user_id = UserId::try_from("@carl:example.com:5000").expect("Failed to create UserId.");
        assert_eq!(user_id.to_string(), "@carl:example.com:5000");
        assert!(!user_id.is_historical());
    }

    #[test]
    fn invalid_characters_in_user_id_localpart() {
        assert_eq!(
            UserId::try_from("@te\nst:example.com").err().unwrap(),
            Error::InvalidCharacters
        );
    }

    #[test]
    fn missing_user_id_sigil() {
        assert_eq!(
            UserId::try_from("carl:example.com").err().unwrap(),
            Error::MissingSigil
        );
    }

    #[test]
    fn missing_user_id_delimiter() {
        assert_eq!(
            UserId::try_from("@carl").err().unwrap(),
            Error::MissingDelimiter
        );
    }

    #[test]
    fn invalid_user_id_host() {
        assert_eq!(
            UserId::try_from("@carl:/").err().unwrap(),
            Error::InvalidHost
        );
    }

    #[test]
    fn invalid_user_id_port() {
        assert_eq!(
            UserId::try_from("@carl:example.com:notaport")
                .err()
                .unwrap(),
            Error::InvalidHost
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>Add pki trait and sphinx header struct<commit_after><|endoftext|>


<commit_before><commit_msg>Added empty decode.rs<commit_after>extern crate rustc_serialize;
<|endoftext|>


<commit_before><commit_msg>Add errors.rs<commit_after>use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::string;

#[derive(Debug)]
pub enum Error {
    Other(String),
    Io(io::Error),
}

pub type Result<T> = ::std::result::Result<T, Error>;

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(err: string::FromUtf8Error) -> Error {
        Error::Other(err.description().to_owned())
    }
}

impl<'a> From<&'a str> for Error {
    fn from(err: &'a str) -> Error {
        Error::Other(err.to_owned())
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::Other(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Other(ref err) => write!(f, "error : {}", err),
            Error::Io(ref err) => write!(f, "io error : {}", err),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Other(ref err) => &err,
            Error::Io(ref err) => err.description(),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Prospective linked-list-based tree type.<commit_after>use ::{Guard, Nav};

use std::cell::{Ref, RefCell};
use std::rc::Rc;
use std::usize;

struct ChildNode<T> {
    tree: Tree<T>,
    prev: Option<Rc<ChildNode<T>>>,
    next: Option<Rc<ChildNode<T>>>,
}

struct TreeInternal<T> {
    data: T, first_child: Option<Rc<RefCell<ChildNode<T>>>>,
}

pub struct Tree<T> {
    internal: Rc<TreeInternal<T>>,
}

pub struct DataGuard<'a, T: 'a> {
    internal: &'a TreeInternal<T>,
}

impl<'a, T: 'a> Guard<'a, T> for DataGuard<'a, T> {
    fn super_deref<'s>(&'s self) -> &'a T {
        &self.internal.data
    }
}

pub struct Navigator<'a, T: 'a> {
    here: &'a Tree<T>, path: Vec<&'a Tree<T>>,
}

impl<'a, T: 'a> Nav<'a> for Navigator<'a, T> {
    type Data = T;
    type DataGuard = DataGuard<'a, T>;

    fn seek_sibling(&mut self, offset: isize) {
        let parent = self.path.pop().expect("Root has no siblings");
        let mut node = parent.internal.first_child;
        loop {
            match node {
                None => panic!["No such sibling"],
                Some(s) if offset == 0 => {
                    self.here = &s.tree;
                    break;
                },
                Some(s) if offset < 0 => {
                    node = s.borrow().prev;
                    offset += 1;
                },
                Some(s) if offset > 0 => {
                    node = s.borrow().next;
                    offset -= 1;
                },
            }
        }
    }

    fn seek_child(&mut self, index: usize) {
        let mut node = &self.here.internal.borrow().first_child;
        loop {
            match node {
                &None => panic!["No such child"],
                &Some(s) if index == 0 => {
                    self.path.push(Tree { internal: self.here.internal.clone() });
                    self.here = Tree { internal: s.borrow().tree.internal.clone() };
                },
                &Some(s) if index > 0 => {
                    node = &s.borrow().next;
                    index -= 1;
                },
            }
        }
    }

    fn at_root(&self) -> bool {
        self.path.is_empty()
    }

    fn to_parent(&mut self) {
        self.here = self.path.pop().expect("Already at root");
    }

    fn to_root(&mut self) {
        if ! self.at_root() {
            self.here = self.path[0];
            self.path.clear();
        }
    }

    fn data(&self) -> DataGuard<'a, T> {
        DataGuard { data: &self.here.internal, }
    }

    fn child_count(&self) -> usize {
        let mut node = &self.here.internal.borrow().first_child;
        for i in 0us.. {
            match node {
                &None => return i,
                &Some(s) => {
                    node = &s.borrow().next;
                    i += 1;
                },
            }
        }
        return usize::MAX;
    }
}
<|endoftext|>


<commit_before><commit_msg>Refactor neighbor calc<commit_after><|endoftext|>


<commit_before><commit_msg>Restyle neighbor print setting<commit_after><|endoftext|>


<commit_before><commit_msg>Fix if/while parsing<commit_after><|endoftext|>


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

//! Feature gating
//!
//! This modules implements the gating necessary for preventing certain compiler
//! features from being used by default. This module will crawl a pre-expanded
//! AST to ensure that there are no features which are used that are not
//! enabled.
//!
//! Features are enabled in programs via the crate-level attributes of
//! #![feature(...)] with a comma-separated list of features.

use middle::lint;

use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::parse::token;

use driver::session::Session;

use std::cell::Cell;

/// This is a list of all known features since the beginning of time. This list
/// can never shrink, it may only be expanded (in order to prevent old programs
/// from failing to compile). The status of each feature may change, however.
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
    ("globs", Active),
    ("macro_rules", Active),
    ("struct_variant", Active),
    ("once_fns", Active),
    ("asm", Active),
    ("managed_boxes", Active),
    ("non_ascii_idents", Active),
    ("thread_local", Active),
    ("link_args", Active),
    ("phase", Active),
    ("plugin_registrar", Active),
    ("log_syntax", Active),
    ("trace_macros", Active),
    ("concat_idents", Active),
    ("unsafe_destructor", Active),

    ("simd", Active),
    ("default_type_params", Active),
    ("quote", Active),
    ("linkage", Active),
    ("struct_inherit", Active),
    ("overloaded_calls", Active),
    ("unboxed_closure_sugar", Active),

    ("quad_precision_float", Active),

    // A temporary feature gate used to enable parser extensions needed
    // to bootstrap fix for #5723.
    ("issue_5723_bootstrap", Active),

    // These are used to test this portion of the compiler, they don't actually
    // mean anything
    ("test_accepted_feature", Accepted),
    ("test_removed_feature", Removed),
];

enum Status {
    /// Represents an active feature that is currently being implemented or
    /// currently being considered for addition/removal.
    Active,

    /// Represents a feature which has since been removed (it was once Active)
    Removed,

    /// This language feature has since been Accepted (it was once Active)
    Accepted,
}

/// A set of features to be used by later passes.
pub struct Features {
    pub default_type_params: Cell<bool>,
    pub quad_precision_float: Cell<bool>,
    pub issue_5723_bootstrap: Cell<bool>,
    pub overloaded_calls: Cell<bool>,
}

impl Features {
    pub fn new() -> Features {
        Features {
            default_type_params: Cell::new(false),
            quad_precision_float: Cell::new(false),
            issue_5723_bootstrap: Cell::new(false),
            overloaded_calls: Cell::new(false),
        }
    }
}

struct Context<'a> {
    features: Vec<&'static str>,
    sess: &'a Session,
}

impl<'a> Context<'a> {
    fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
        if !self.has_feature(feature) {
            self.sess.span_err(span, explain);
            self.sess.span_note(span, format!("add #![feature({})] to the \
                                               crate attributes to enable",
                                              feature).as_slice());
        }
    }

    fn gate_box(&self, span: Span) {
        self.gate_feature("managed_boxes", span,
                          "The managed box syntax is being replaced by the \
                           `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
                           functionality to managed trait objects will be \
                           implemented but is currently missing.");
    }

    fn has_feature(&self, feature: &str) -> bool {
        self.features.iter().any(|n| n.as_slice() == feature)
    }
}

impl<'a> Visitor<()> for Context<'a> {
    fn visit_ident(&mut self, sp: Span, id: ast::Ident, _: ()) {
        if !token::get_ident(id).get().is_ascii() {
            self.gate_feature("non_ascii_idents", sp,
                              "non-ascii idents are not fully supported.");
        }
    }

    fn visit_view_item(&mut self, i: &ast::ViewItem, _: ()) {
        match i.node {
            ast::ViewItemUse(ref path) => {
                match path.node {
                    ast::ViewPathGlob(..) => {
                        self.gate_feature("globs", path.span,
                                          "glob import statements are \
                                           experimental and possibly buggy");
                    }
                    _ => {}
                }
            }
            ast::ViewItemExternCrate(..) => {
                for attr in i.attrs.iter() {
                    if attr.name().get() == "phase"{
                        self.gate_feature("phase", attr.span,
                                          "compile time crate loading is \
                                           experimental and possibly buggy");
                    }
                }
            }
        }
        visit::walk_view_item(self, i, ())
    }

    fn visit_item(&mut self, i: &ast::Item, _:()) {
        for attr in i.attrs.iter() {
            if attr.name().equiv(&("thread_local")) {
                self.gate_feature("thread_local", i.span,
                                  "`#[thread_local]` is an experimental feature, and does not \
                                  currently handle destructors. There is no corresponding \
                                  `#[task_local]` mapping to the task model");
            }
        }
        match i.node {
            ast::ItemEnum(ref def, _) => {
                for variant in def.variants.iter() {
                    match variant.node.kind {
                        ast::StructVariantKind(..) => {
                            self.gate_feature("struct_variant", variant.span,
                                              "enum struct variants are \
                                               experimental and possibly buggy");
                        }
                        _ => {}
                    }
                }
            }

            ast::ItemForeignMod(..) => {
                if attr::contains_name(i.attrs.as_slice(), "link_args") {
                    self.gate_feature("link_args", i.span,
                                      "the `link_args` attribute is not portable \
                                       across platforms, it is recommended to \
                                       use `#[link(name = \"foo\")]` instead")
                }
            }

            ast::ItemFn(..) => {
                if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
                    self.gate_feature("plugin_registrar", i.span,
                                      "compiler plugins are experimental and possibly buggy");
                }
            }

            ast::ItemStruct(struct_definition, _) => {
                if attr::contains_name(i.attrs.as_slice(), "simd") {
                    self.gate_feature("simd", i.span,
                                      "SIMD types are experimental and possibly buggy");
                }
                match struct_definition.super_struct {
                    Some(ref path) => self.gate_feature("struct_inherit", path.span,
                                                        "struct inheritance is experimental \
                                                         and possibly buggy"),
                    None => {}
                }
                if struct_definition.is_virtual {
                    self.gate_feature("struct_inherit", i.span,
                                      "struct inheritance (`virtual` keyword) is \
                                       experimental and possibly buggy");
                }
            }

            ast::ItemImpl(..) => {
                if attr::contains_name(i.attrs.as_slice(),
                                       "unsafe_destructor") {
                    self.gate_feature("unsafe_destructor",
                                      i.span,
                                      "`#[unsafe_destructor]` allows too \
                                       many unsafe patterns and may be \
                                       removed in the future");
                }
            }

            _ => {}
        }

        visit::walk_item(self, i, ());
    }

    fn visit_mac(&mut self, macro: &ast::Mac, _: ()) {
        let ast::MacInvocTT(ref path, _, _) = macro.node;
        let id = path.segments.last().unwrap().identifier;
        let quotes = ["quote_tokens", "quote_expr", "quote_ty",
                      "quote_item", "quote_pat", "quote_stmt"];
        let msg = " is not stable enough for use and are subject to change";

        if id == token::str_to_ident("macro_rules") {
            self.gate_feature("macro_rules", path.span, "macro definitions are \
                not stable enough for use and are subject to change");
        }

        else if id == token::str_to_ident("asm") {
            self.gate_feature("asm", path.span, "inline assembly is not \
                stable enough for use and is subject to change");
        }

        else if id == token::str_to_ident("log_syntax") {
            self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
                stable enough for use and is subject to change");
        }

        else if id == token::str_to_ident("trace_macros") {
            self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
                stable enough for use and is subject to change");
        }

        else if id == token::str_to_ident("concat_idents") {
            self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
                stable enough for use and is subject to change");
        }

        else {
            for &quote in quotes.iter() {
                if id == token::str_to_ident(quote) {
                  self.gate_feature("quote",
                                    path.span,
                                    format!("{}{}", quote, msg).as_slice());
                }
            }
        }
    }

    fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
        match i.node {
            ast::ForeignItemFn(..) | ast::ForeignItemStatic(..) => {
                if attr::contains_name(i.attrs.as_slice(), "linkage") {
                    self.gate_feature("linkage", i.span,
                                      "the `linkage` attribute is experimental \
                                       and not portable across platforms")
                }
            }
        }
        visit::walk_foreign_item(self, i, ())
    }

    fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
        match t.node {
            ast::TyClosure(closure, _) if closure.onceness == ast::Once => {
                self.gate_feature("once_fns", t.span,
                                  "once functions are \
                                   experimental and likely to be removed");

            },
            ast::TyBox(_) => { self.gate_box(t.span); }
            ast::TyUnboxedFn(_) => {
                self.gate_feature("unboxed_closure_sugar",
                                  t.span,
                                  "unboxed closure trait sugar is experimental");
            }
            _ => {}
        }

        visit::walk_ty(self, t, ());
    }

    fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
        match e.node {
            ast::ExprUnary(ast::UnBox, _) => {
                self.gate_box(e.span);
            }
            _ => {}
        }
        visit::walk_expr(self, e, ());
    }

    fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
        for type_parameter in generics.ty_params.iter() {
            match type_parameter.default {
                Some(ty) => {
                    self.gate_feature("default_type_params", ty.span,
                                      "default type parameters are \
                                       experimental and possibly buggy");
                }
                None => {}
            }
        }
        visit::walk_generics(self, generics, ());
    }
}

pub fn check_crate(sess: &Session, krate: &ast::Crate) {
    let mut cx = Context {
        features: Vec::new(),
        sess: sess,
    };

    for attr in krate.attrs.iter() {
        if !attr.check_name("feature") {
            continue
        }

        match attr.meta_item_list() {
            None => {
                sess.span_err(attr.span, "malformed feature attribute, \
                                          expected #![feature(...)]");
            }
            Some(list) => {
                for &mi in list.iter() {
                    let name = match mi.node {
                        ast::MetaWord(ref word) => (*word).clone(),
                        _ => {
                            sess.span_err(mi.span,
                                          "malformed feature, expected just \
                                           one word");
                            continue
                        }
                    };
                    match KNOWN_FEATURES.iter()
                                        .find(|& &(n, _)| name.equiv(&n)) {
                        Some(&(name, Active)) => { cx.features.push(name); }
                        Some(&(_, Removed)) => {
                            sess.span_err(mi.span, "feature has been removed");
                        }
                        Some(&(_, Accepted)) => {
                            sess.span_warn(mi.span, "feature has added to rust, \
                                                     directive not necessary");
                        }
                        None => {
                            sess.add_lint(lint::UnknownFeatures,
                                          ast::CRATE_NODE_ID,
                                          mi.span,
                                          "unknown feature".to_string());
                        }
                    }
                }
            }
        }
    }

    visit::walk_crate(&mut cx, krate, ());

    sess.abort_if_errors();

    sess.features.default_type_params.set(cx.has_feature("default_type_params"));
    sess.features.quad_precision_float.set(cx.has_feature("quad_precision_float"));
    sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
    sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
}
<commit_msg>librustc: Fix poorly formatted doc in feature_gate<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Feature gating
//!
//! This modules implements the gating necessary for preventing certain compiler
//! features from being used by default. This module will crawl a pre-expanded
//! AST to ensure that there are no features which are used that are not
//! enabled.
//!
//! Features are enabled in programs via the crate-level attributes of
//! `#![feature(...)]` with a comma-separated list of features.

use middle::lint;

use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::parse::token;

use driver::session::Session;

use std::cell::Cell;

/// This is a list of all known features since the beginning of time. This list
/// can never shrink, it may only be expanded (in order to prevent old programs
/// from failing to compile). The status of each feature may change, however.
static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
    ("globs", Active),
    ("macro_rules", Active),
    ("struct_variant", Active),
    ("once_fns", Active),
    ("asm", Active),
    ("managed_boxes", Active),
    ("non_ascii_idents", Active),
    ("thread_local", Active),
    ("link_args", Active),
    ("phase", Active),
    ("plugin_registrar", Active),
    ("log_syntax", Active),
    ("trace_macros", Active),
    ("concat_idents", Active),
    ("unsafe_destructor", Active),

    ("simd", Active),
    ("default_type_params", Active),
    ("quote", Active),
    ("linkage", Active),
    ("struct_inherit", Active),
    ("overloaded_calls", Active),
    ("unboxed_closure_sugar", Active),

    ("quad_precision_float", Active),

    // A temporary feature gate used to enable parser extensions needed
    // to bootstrap fix for #5723.
    ("issue_5723_bootstrap", Active),

    // These are used to test this portion of the compiler, they don't actually
    // mean anything
    ("test_accepted_feature", Accepted),
    ("test_removed_feature", Removed),
];

enum Status {
    /// Represents an active feature that is currently being implemented or
    /// currently being considered for addition/removal.
    Active,

    /// Represents a feature which has since been removed (it was once Active)
    Removed,

    /// This language feature has since been Accepted (it was once Active)
    Accepted,
}

/// A set of features to be used by later passes.
pub struct Features {
    pub default_type_params: Cell<bool>,
    pub quad_precision_float: Cell<bool>,
    pub issue_5723_bootstrap: Cell<bool>,
    pub overloaded_calls: Cell<bool>,
}

impl Features {
    pub fn new() -> Features {
        Features {
            default_type_params: Cell::new(false),
            quad_precision_float: Cell::new(false),
            issue_5723_bootstrap: Cell::new(false),
            overloaded_calls: Cell::new(false),
        }
    }
}

struct Context<'a> {
    features: Vec<&'static str>,
    sess: &'a Session,
}

impl<'a> Context<'a> {
    fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
        if !self.has_feature(feature) {
            self.sess.span_err(span, explain);
            self.sess.span_note(span, format!("add #![feature({})] to the \
                                               crate attributes to enable",
                                              feature).as_slice());
        }
    }

    fn gate_box(&self, span: Span) {
        self.gate_feature("managed_boxes", span,
                          "The managed box syntax is being replaced by the \
                           `std::gc::Gc` and `std::rc::Rc` types. Equivalent \
                           functionality to managed trait objects will be \
                           implemented but is currently missing.");
    }

    fn has_feature(&self, feature: &str) -> bool {
        self.features.iter().any(|n| n.as_slice() == feature)
    }
}

impl<'a> Visitor<()> for Context<'a> {
    fn visit_ident(&mut self, sp: Span, id: ast::Ident, _: ()) {
        if !token::get_ident(id).get().is_ascii() {
            self.gate_feature("non_ascii_idents", sp,
                              "non-ascii idents are not fully supported.");
        }
    }

    fn visit_view_item(&mut self, i: &ast::ViewItem, _: ()) {
        match i.node {
            ast::ViewItemUse(ref path) => {
                match path.node {
                    ast::ViewPathGlob(..) => {
                        self.gate_feature("globs", path.span,
                                          "glob import statements are \
                                           experimental and possibly buggy");
                    }
                    _ => {}
                }
            }
            ast::ViewItemExternCrate(..) => {
                for attr in i.attrs.iter() {
                    if attr.name().get() == "phase"{
                        self.gate_feature("phase", attr.span,
                                          "compile time crate loading is \
                                           experimental and possibly buggy");
                    }
                }
            }
        }
        visit::walk_view_item(self, i, ())
    }

    fn visit_item(&mut self, i: &ast::Item, _:()) {
        for attr in i.attrs.iter() {
            if attr.name().equiv(&("thread_local")) {
                self.gate_feature("thread_local", i.span,
                                  "`#[thread_local]` is an experimental feature, and does not \
                                  currently handle destructors. There is no corresponding \
                                  `#[task_local]` mapping to the task model");
            }
        }
        match i.node {
            ast::ItemEnum(ref def, _) => {
                for variant in def.variants.iter() {
                    match variant.node.kind {
                        ast::StructVariantKind(..) => {
                            self.gate_feature("struct_variant", variant.span,
                                              "enum struct variants are \
                                               experimental and possibly buggy");
                        }
                        _ => {}
                    }
                }
            }

            ast::ItemForeignMod(..) => {
                if attr::contains_name(i.attrs.as_slice(), "link_args") {
                    self.gate_feature("link_args", i.span,
                                      "the `link_args` attribute is not portable \
                                       across platforms, it is recommended to \
                                       use `#[link(name = \"foo\")]` instead")
                }
            }

            ast::ItemFn(..) => {
                if attr::contains_name(i.attrs.as_slice(), "plugin_registrar") {
                    self.gate_feature("plugin_registrar", i.span,
                                      "compiler plugins are experimental and possibly buggy");
                }
            }

            ast::ItemStruct(struct_definition, _) => {
                if attr::contains_name(i.attrs.as_slice(), "simd") {
                    self.gate_feature("simd", i.span,
                                      "SIMD types are experimental and possibly buggy");
                }
                match struct_definition.super_struct {
                    Some(ref path) => self.gate_feature("struct_inherit", path.span,
                                                        "struct inheritance is experimental \
                                                         and possibly buggy"),
                    None => {}
                }
                if struct_definition.is_virtual {
                    self.gate_feature("struct_inherit", i.span,
                                      "struct inheritance (`virtual` keyword) is \
                                       experimental and possibly buggy");
                }
            }

            ast::ItemImpl(..) => {
                if attr::contains_name(i.attrs.as_slice(),
                                       "unsafe_destructor") {
                    self.gate_feature("unsafe_destructor",
                                      i.span,
                                      "`#[unsafe_destructor]` allows too \
                                       many unsafe patterns and may be \
                                       removed in the future");
                }
            }

            _ => {}
        }

        visit::walk_item(self, i, ());
    }

    fn visit_mac(&mut self, macro: &ast::Mac, _: ()) {
        let ast::MacInvocTT(ref path, _, _) = macro.node;
        let id = path.segments.last().unwrap().identifier;
        let quotes = ["quote_tokens", "quote_expr", "quote_ty",
                      "quote_item", "quote_pat", "quote_stmt"];
        let msg = " is not stable enough for use and are subject to change";

        if id == token::str_to_ident("macro_rules") {
            self.gate_feature("macro_rules", path.span, "macro definitions are \
                not stable enough for use and are subject to change");
        }

        else if id == token::str_to_ident("asm") {
            self.gate_feature("asm", path.span, "inline assembly is not \
                stable enough for use and is subject to change");
        }

        else if id == token::str_to_ident("log_syntax") {
            self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
                stable enough for use and is subject to change");
        }

        else if id == token::str_to_ident("trace_macros") {
            self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
                stable enough for use and is subject to change");
        }

        else if id == token::str_to_ident("concat_idents") {
            self.gate_feature("concat_idents", path.span, "`concat_idents` is not \
                stable enough for use and is subject to change");
        }

        else {
            for &quote in quotes.iter() {
                if id == token::str_to_ident(quote) {
                  self.gate_feature("quote",
                                    path.span,
                                    format!("{}{}", quote, msg).as_slice());
                }
            }
        }
    }

    fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
        match i.node {
            ast::ForeignItemFn(..) | ast::ForeignItemStatic(..) => {
                if attr::contains_name(i.attrs.as_slice(), "linkage") {
                    self.gate_feature("linkage", i.span,
                                      "the `linkage` attribute is experimental \
                                       and not portable across platforms")
                }
            }
        }
        visit::walk_foreign_item(self, i, ())
    }

    fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
        match t.node {
            ast::TyClosure(closure, _) if closure.onceness == ast::Once => {
                self.gate_feature("once_fns", t.span,
                                  "once functions are \
                                   experimental and likely to be removed");

            },
            ast::TyBox(_) => { self.gate_box(t.span); }
            ast::TyUnboxedFn(_) => {
                self.gate_feature("unboxed_closure_sugar",
                                  t.span,
                                  "unboxed closure trait sugar is experimental");
            }
            _ => {}
        }

        visit::walk_ty(self, t, ());
    }

    fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
        match e.node {
            ast::ExprUnary(ast::UnBox, _) => {
                self.gate_box(e.span);
            }
            _ => {}
        }
        visit::walk_expr(self, e, ());
    }

    fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
        for type_parameter in generics.ty_params.iter() {
            match type_parameter.default {
                Some(ty) => {
                    self.gate_feature("default_type_params", ty.span,
                                      "default type parameters are \
                                       experimental and possibly buggy");
                }
                None => {}
            }
        }
        visit::walk_generics(self, generics, ());
    }
}

pub fn check_crate(sess: &Session, krate: &ast::Crate) {
    let mut cx = Context {
        features: Vec::new(),
        sess: sess,
    };

    for attr in krate.attrs.iter() {
        if !attr.check_name("feature") {
            continue
        }

        match attr.meta_item_list() {
            None => {
                sess.span_err(attr.span, "malformed feature attribute, \
                                          expected #![feature(...)]");
            }
            Some(list) => {
                for &mi in list.iter() {
                    let name = match mi.node {
                        ast::MetaWord(ref word) => (*word).clone(),
                        _ => {
                            sess.span_err(mi.span,
                                          "malformed feature, expected just \
                                           one word");
                            continue
                        }
                    };
                    match KNOWN_FEATURES.iter()
                                        .find(|& &(n, _)| name.equiv(&n)) {
                        Some(&(name, Active)) => { cx.features.push(name); }
                        Some(&(_, Removed)) => {
                            sess.span_err(mi.span, "feature has been removed");
                        }
                        Some(&(_, Accepted)) => {
                            sess.span_warn(mi.span, "feature has added to rust, \
                                                     directive not necessary");
                        }
                        None => {
                            sess.add_lint(lint::UnknownFeatures,
                                          ast::CRATE_NODE_ID,
                                          mi.span,
                                          "unknown feature".to_string());
                        }
                    }
                }
            }
        }
    }

    visit::walk_crate(&mut cx, krate, ());

    sess.abort_if_errors();

    sess.features.default_type_params.set(cx.has_feature("default_type_params"));
    sess.features.quad_precision_float.set(cx.has_feature("quad_precision_float"));
    sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
    sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
}
<|endoftext|>