<commit_before>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
pub struct Group<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<'a, K, V, S> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<'a, K, V, RandomState> {
        Default::default()
    }

    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<'a, K, V, S> {
        GroupBuilder {
            map: PhantomData,
            capacity: 0,
            signals: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let map = &mut self.map;
        self.active.as_mut().and_then(move |active| map.get_mut(active))
    }

    /// Sets the current active item in the group.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: K) -> Option<K> {
        if self.map.contains_key(&k) {
            if self.active.as_ref().map_or(false, |a| a != &k) {
                if let Some(ref mut f) = self.signals {
                    f(Some(&k))
                }
            }
            self.active = Some(k);
            None
        } else {
            Some(k)
        }
    }

    /// Unsets the current active item in the group.
    #[inline]
    pub fn unset(&mut self) {
        if self.active.is_some() {
            if let Some(ref mut f) = self.signals {
                f(None);
            }
        }
        self.active = None;
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        self.get_mut().and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Record<'a, R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_saved())
    }

    /// Calls the [`set_unsaved`] method on the active record.
    ///
    /// [`set_unsaved`]: record/struct.Record.html#method.set_unsaved
    #[inline]
    pub fn set_unsaved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_unsaved())
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> Option<bool> {
        self.get().map(|stack| stack.is_saved())
    }

    /// Calls the [`push`] method on the active record.
    ///
    /// [`push`]: record/struct.Record.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |record| record.push(cmd))
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.undo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    pub fn to_undo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    pub fn to_redo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_redo_string())
    }
}

impl<'a, K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("map", &self.map)
            .field("active", &self.active)
            .finish()
    }
}

impl<'a, K: Hash + Eq + Display, V: Display> Display for Group<'a, K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.map {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, " -> {}:\n    {}", key, item)?;
            } else {
                writeln!(f, "    {}:\n    {}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<'a, K: Hash + Eq, V> Default for Group<'a, K, V, RandomState> {
    #[inline]
    fn default() -> Group<'a, K, V, RandomState> {
        Group {
            map: HashMap::new(),
            active: None,
            signals: None,
        }
    }
}

/// Builder for a group.
pub struct GroupBuilder<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: PhantomData<(K, V, S)>,
    capacity: usize,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> GroupBuilder<'a, K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<'a, K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> GroupBuilder<'a, K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<'a, K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::*;
    /// # let _: Group<u8, u8> =
    /// Group::builder()
    ///     .signals(|k| match k {
    ///         Some(k) => println!("The new active stack is {}.", k),
    ///         None => println!("No active stack."),
    ///     })
    ///     .build();
    /// ```
    #[inline]
    pub fn signals<F>(mut self, f: F) -> GroupBuilder<'a, K, V, S>
    where
        F: FnMut(Option<&K>) + Send + Sync + 'a
    {
        self.signals = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<'a, K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signals: self.signals,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("map", &self.map)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<commit_msg>Fix unset method<commit_after>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
pub struct Group<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<'a, K, V, S> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<'a, K, V, RandomState> {
        Default::default()
    }

    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<'a, K, V, S> {
        GroupBuilder {
            map: PhantomData,
            capacity: 0,
            signals: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let map = &mut self.map;
        self.active.as_mut().and_then(move |active| map.get_mut(active))
    }

    /// Sets the current active item in the group.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: K) -> Option<K> {
        if self.map.contains_key(&k) {
            if self.active.as_ref().map_or(false, |a| a != &k) {
                if let Some(ref mut f) = self.signals {
                    f(Some(&k))
                }
            }
            self.active = Some(k);
            None
        } else {
            Some(k)
        }
    }

    /// Unsets the current active item in the group.
    #[inline]
    pub fn unset(&mut self) {
        if self.active.is_some() {
            self.active = None;
            if let Some(ref mut f) = self.signals {
                f(None);
            }
        }
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        self.get_mut().and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Record<'a, R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_saved())
    }

    /// Calls the [`set_unsaved`] method on the active record.
    ///
    /// [`set_unsaved`]: record/struct.Record.html#method.set_unsaved
    #[inline]
    pub fn set_unsaved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_unsaved())
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> Option<bool> {
        self.get().map(|stack| stack.is_saved())
    }

    /// Calls the [`push`] method on the active record.
    ///
    /// [`push`]: record/struct.Record.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |record| record.push(cmd))
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.undo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    pub fn to_undo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    pub fn to_redo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_redo_string())
    }
}

impl<'a, K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("map", &self.map)
            .field("active", &self.active)
            .finish()
    }
}

impl<'a, K: Hash + Eq + Display, V: Display> Display for Group<'a, K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.map {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, " -> {}:\n    {}", key, item)?;
            } else {
                writeln!(f, "    {}:\n    {}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<'a, K: Hash + Eq, V> Default for Group<'a, K, V, RandomState> {
    #[inline]
    fn default() -> Group<'a, K, V, RandomState> {
        Group {
            map: HashMap::new(),
            active: None,
            signals: None,
        }
    }
}

/// Builder for a group.
pub struct GroupBuilder<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: PhantomData<(K, V, S)>,
    capacity: usize,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> GroupBuilder<'a, K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<'a, K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> GroupBuilder<'a, K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<'a, K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::*;
    /// # let _: Group<u8, u8> =
    /// Group::builder()
    ///     .signals(|k| match k {
    ///         Some(k) => println!("The new active stack is {}.", k),
    ///         None => println!("No active stack."),
    ///     })
    ///     .build();
    /// ```
    #[inline]
    pub fn signals<F>(mut self, f: F) -> GroupBuilder<'a, K, V, S>
    where
        F: FnMut(Option<&K>) + Send + Sync + 'a
    {
        self.signals = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<'a, K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signals: self.signals,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("map", &self.map)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<|endoftext|>


<commit_before>//! This is initial draft implementation of HTTP/1.x protocol. It's based
//! on `rotor::transports::greedy_stream` which is not very DDoS-safe. Also
//! this implementation has hard-coded limits on certain request parameters.
//! Otherwise implementation should be good enough for general consumption
//!
//!
use std::io::Write;
use std::error::Error;
use std::mem::replace;

use time::now_utc;
use rotor::transports::greedy_stream::{Transport, Protocol};
use rotor::buffer_util::find_substr;
use hyper::version::HttpVersion;
use hyper::method::Method;
use hyper::header::{Headers, Date, HttpDate, ContentLength};
use hyper::uri::RequestUri;
use hyper::status::StatusCode;
use httparse;

/// Note httparse requires we preallocate array of this size so be wise
pub const MAX_HEADERS_NUM: usize = 256;
/// This one is not preallocated, but too large buffer is of limited use
/// because of previous parameter.
pub const MAX_HEADERS_SIZE: usize = 16384;
/// This is not "enough for everyone" but we probably need some limit anyway.
/// Note that underlying `netbuf` impl limited to a little less than 4GiB
pub const MAX_BODY_SIZE: usize = 104_856_700;

pub trait Handler {
    /// Dispatched when request arrives.
    ///
    /// We don't support POST body yet, so this is only one callback, but will
    /// probably be split into many in future
    fn request(request: Request, response: &mut ResponseBuilder) {
        // The 404 or BadRequest for all requests
    }
}

#[derive(Debug)]
pub enum ResponseFsm {
    Head {
        status: StatusCode,
        version: HttpVersion,
        headers: Headers,
    },
    // TODO(tailhook) WritingFixed { bytes_remaining: u64 }
    // TODO(tailhook) WritingChunked
    End,
}

pub struct ResponseBuilder<'a, 'b: 'a>{
    state: ResponseFsm,
    transport: &'a mut Transport<'b>,
}

pub enum Client<H:Handler+Send> {
    Initial,
    ReadHeaders,  // TODO(tailhook) 100 Expect?
    Processing(H),
    // ReadFixedSize(Request, usize),  // TODO
    // ReadChunked(Request, usize),
    KeepAlive,
}

#[derive(Debug)]
pub struct Request {
    pub version: HttpVersion,
    pub method: Method,
    pub uri: RequestUri,
    pub headers: Headers,
    pub body: Vec<u8>,
}

fn parse_headers(transport: &mut Transport)
    -> Result<Option<Request>, Box<Error+Send+Sync>>
{
    use self::Client::*;
    use hyper::version::HttpVersion::*;

    let mut buf = transport.input();
    let headers_end = match find_substr(&buf[..], b"\r\n\r\n") {
        Some(x) => x,
        None => { return Ok(None); }
    };
    let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS_NUM];
    let req = {
        let mut raw = httparse::Request::new(&mut headers);
        match raw.parse(&buf[..]) {
            Ok(httparse::Status::Complete(x)) => {
                assert!(x == headers_end+4);
            }
            Ok(_) => unreachable!(),
            Err(_) => {
                return Err(From::from("Header syntax mismatch"));
            }
        }
        Request {
            version: if raw.version.unwrap() == 1 { Http11 } else { Http10 },
            method: try!(raw.method.unwrap().parse()),
            uri: try!(raw.path.unwrap().parse()),
            headers: try!(Headers::from_raw(raw.headers)),
            body: Vec::new(),
        }
    };
    buf.consume(headers_end+4);
    Ok(Some(req))
}

impl<H: Handler+Send> Client<H> {
    fn handle_request(&self, req: Request, transport: &mut Transport) {
        let mut bld = ResponseBuilder {
            state: ResponseFsm::Head {
                status: if req.method == Method::Get
                    { StatusCode::NotFound } else { StatusCode::BadRequest },
                version: req.version,
                headers: Headers::new(),
            },
            transport: transport,
        };
        <H as Handler>::request(req, &mut bld);
        bld.default_body();
    }
}

impl<H: Handler+Send> Protocol for Client<H> {
    fn accepted() -> Self {
        Client::Initial
    }
    fn data_received(self, transport: &mut Transport) -> Option<Self> {
        use self::Client::*;
        match self {
            // We keep Initial and KeepAlive states separate from
            // ReadHeaders just for debugging and for potentially different
            // timeouts in future
            Initial|ReadHeaders|KeepAlive => {
                match parse_headers(transport) {
                    Err(e) => {
                        debug!("Error parsing HTTP headers: {}", e);
                        None
                    }
                    Ok(None) => {
                        Some(ReadHeaders)
                    }
                    Ok(Some(req)) => {
                        self.handle_request(req, transport);
                        Some(KeepAlive)
                    }
                }
            }
            Processing(h) => {
                unimplemented!();
            }
        }
    }
}

impl<'a, 'b> ResponseBuilder<'a, 'b> {

    /// Write request body in a single go
    pub fn put_body<B:AsRef<[u8]>>(&mut self, body: B) {
        use self::ResponseFsm::*;
        match replace(&mut self.state, End) {
            Head { status, version, mut headers } => {
                let body = body.as_ref();
                let out = self.transport.output();
                write!(out, "{} {}\r\n", version, status).unwrap();
                if !headers.has::<Date>() {
                    headers.set(Date(HttpDate(now_utc())));
                }
                headers.set(ContentLength(body.len() as u64));
                write!(out, "{}\r\n", headers).unwrap();
                out.extend(body);
            }
            state => {
                panic!("Too late to send body in state: {:?}", state);
            }
        }
    }

    pub fn set_status(&mut self, new_status: StatusCode) {
        use self::ResponseFsm::*;
        match self.state {
            Head { ref mut status, .. } => {
                *status = new_status;
            }
            ref state => {
                panic!("Too late to set status in state: {:?}", state);
            }
        }
    }

    pub fn default_body(&mut self) {
        use self::ResponseFsm::*;
        match self.state {
            Head { status, .. } => {
                // TODO(tailhook) maybe assert on 200 Ok status?
                self.put_body(&format!("{}", status));
                self.state = End;
            }
            End => {}
        }
    }
}
<commit_msg>Get rid of warnings<commit_after>//! This is initial draft implementation of HTTP/1.x protocol. It's based
//! on `rotor::transports::greedy_stream` which is not very DDoS-safe. Also
//! this implementation has hard-coded limits on certain request parameters.
//! Otherwise implementation should be good enough for general consumption
//!
//!
use std::io::Write;
use std::error::Error;
use std::mem::replace;

use time::now_utc;
use rotor::transports::greedy_stream::{Transport, Protocol};
use rotor::buffer_util::find_substr;
use hyper::version::HttpVersion;
use hyper::method::Method;
use hyper::header::{Headers, Date, HttpDate, ContentLength};
use hyper::uri::RequestUri;
use hyper::status::StatusCode;
use httparse;

/// Note httparse requires we preallocate array of this size so be wise
pub const MAX_HEADERS_NUM: usize = 256;
/// This one is not preallocated, but too large buffer is of limited use
/// because of previous parameter.
pub const MAX_HEADERS_SIZE: usize = 16384;
/// This is not "enough for everyone" but we probably need some limit anyway.
/// Note that underlying `netbuf` impl limited to a little less than 4GiB
pub const MAX_BODY_SIZE: usize = 104_856_700;

pub trait Handler {
    /// Dispatched when request arrives.
    ///
    /// We don't support POST body yet, so this is only one callback, but will
    /// probably be split into many in future
    fn request(_request: Request, _response: &mut ResponseBuilder) {
        // The 404 or BadRequest for all requests
    }
}

#[derive(Debug)]
pub enum ResponseFsm {
    Head {
        status: StatusCode,
        version: HttpVersion,
        headers: Headers,
    },
    // TODO(tailhook) WritingFixed { bytes_remaining: u64 }
    // TODO(tailhook) WritingChunked
    End,
}

pub struct ResponseBuilder<'a, 'b: 'a>{
    state: ResponseFsm,
    transport: &'a mut Transport<'b>,
}

pub enum Client<H:Handler+Send> {
    Initial,
    ReadHeaders,  // TODO(tailhook) 100 Expect?
    Processing(H),
    // ReadFixedSize(Request, usize),  // TODO
    // ReadChunked(Request, usize),
    KeepAlive,
}

#[derive(Debug)]
pub struct Request {
    pub version: HttpVersion,
    pub method: Method,
    pub uri: RequestUri,
    pub headers: Headers,
    pub body: Vec<u8>,
}

fn parse_headers(transport: &mut Transport)
    -> Result<Option<Request>, Box<Error+Send+Sync>>
{
    use hyper::version::HttpVersion::*;

    let mut buf = transport.input();
    let headers_end = match find_substr(&buf[..], b"\r\n\r\n") {
        Some(x) => x,
        None => { return Ok(None); }
    };
    let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS_NUM];
    let req = {
        let mut raw = httparse::Request::new(&mut headers);
        match raw.parse(&buf[..]) {
            Ok(httparse::Status::Complete(x)) => {
                assert!(x == headers_end+4);
            }
            Ok(_) => unreachable!(),
            Err(_) => {
                return Err(From::from("Header syntax mismatch"));
            }
        }
        Request {
            version: if raw.version.unwrap() == 1 { Http11 } else { Http10 },
            method: try!(raw.method.unwrap().parse()),
            uri: try!(raw.path.unwrap().parse()),
            headers: try!(Headers::from_raw(raw.headers)),
            body: Vec::new(),
        }
    };
    buf.consume(headers_end+4);
    Ok(Some(req))
}

impl<H: Handler+Send> Client<H> {
    fn handle_request(&self, req: Request, transport: &mut Transport) {
        let mut bld = ResponseBuilder {
            state: ResponseFsm::Head {
                status: if req.method == Method::Get
                    { StatusCode::NotFound } else { StatusCode::BadRequest },
                version: req.version,
                headers: Headers::new(),
            },
            transport: transport,
        };
        <H as Handler>::request(req, &mut bld);
        bld.default_body();
    }
}

impl<H: Handler+Send> Protocol for Client<H> {
    fn accepted() -> Self {
        Client::Initial
    }
    fn data_received(self, transport: &mut Transport) -> Option<Self> {
        use self::Client::*;
        match self {
            // We keep Initial and KeepAlive states separate from
            // ReadHeaders just for debugging and for potentially different
            // timeouts in future
            Initial|ReadHeaders|KeepAlive => {
                match parse_headers(transport) {
                    Err(e) => {
                        debug!("Error parsing HTTP headers: {}", e);
                        None
                    }
                    Ok(None) => {
                        Some(ReadHeaders)
                    }
                    Ok(Some(req)) => {
                        self.handle_request(req, transport);
                        Some(KeepAlive)
                    }
                }
            }
            Processing(_) => {
                unimplemented!();
            }
        }
    }
}

impl<'a, 'b> ResponseBuilder<'a, 'b> {

    /// Write request body in a single go
    pub fn put_body<B:AsRef<[u8]>>(&mut self, body: B) {
        use self::ResponseFsm::*;
        match replace(&mut self.state, End) {
            Head { status, version, mut headers } => {
                let body = body.as_ref();
                let out = self.transport.output();
                write!(out, "{} {}\r\n", version, status).unwrap();
                if !headers.has::<Date>() {
                    headers.set(Date(HttpDate(now_utc())));
                }
                headers.set(ContentLength(body.len() as u64));
                write!(out, "{}\r\n", headers).unwrap();
                out.extend(body);
            }
            state => {
                panic!("Too late to send body in state: {:?}", state);
            }
        }
    }

    pub fn set_status(&mut self, new_status: StatusCode) {
        use self::ResponseFsm::*;
        match self.state {
            Head { ref mut status, .. } => {
                *status = new_status;
            }
            ref state => {
                panic!("Too late to set status in state: {:?}", state);
            }
        }
    }

    pub fn default_body(&mut self) {
        use self::ResponseFsm::*;
        match self.state {
            Head { status, .. } => {
                // TODO(tailhook) maybe assert on 200 Ok status?
                self.put_body(&format!("{}", status));
                self.state = End;
            }
            End => {}
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

extern crate libc;
extern crate termkey;

use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::thread;

use self::termkey::{TermKeyEvent, TermKeyResult};
use self::termkey::c::TermKeySym;

use keymap;

#[cfg(not(test))]
const STDIN_FILENO: libc::c_int = 0;

/*
 * TermInput is returned when starting listening for key events on a file
 * descriptor. It controls the life time of the terminal input loop. When the
 * TermInput is dropped, the terminal input loop will finish.
 */
pub struct TermInput {
  kill_tx: Sender<()>,
  died_rx: Receiver<()>,
}

impl Drop for TermInput {
  fn drop(&mut self) {
    self.kill_tx.send(()).unwrap();
    self.died_rx.recv().unwrap();
  }
}

// start listening for terminal input on stdin
#[cfg(not(test))]
pub fn start(key_tx: Sender<keymap::Key>) -> TermInput {
  start_on_fd(STDIN_FILENO, key_tx)
}

// start listening for terminal input on the specified file descriptor
pub fn start_on_fd(fd: libc::c_int, key_tx: Sender<keymap::Key>) -> TermInput {
  let (kill_tx, kill_rx) = channel();
  let (died_tx, died_rx) = channel();
  thread::spawn(move || { input_loop(kill_rx, died_tx, key_tx, fd); });
  TermInput { kill_tx: kill_tx, died_rx: died_rx }
}

/*
 * Helper module for detecting available bytes on the file descriptor being
 * listened to.
 */
mod libc_poll {
  use super::libc::{c_int, c_long, c_short};

  #[repr(C)]
  struct Pollfd {
    fd: c_int,
    events: c_short,
    revents: c_short
  }

  extern {
    fn poll(fds: *mut Pollfd, nfds: c_long, timeout: c_int) -> c_int;
  }

  #[derive(PartialEq)]
  pub enum PollResult {
    Ready,
    Timeout,
  }

  pub fn poll_fd(fd: c_int, timeout_ms: int) -> PollResult {
    const POLLIN: c_short = 1;
    let mut pollfd = Pollfd { fd: fd, events: POLLIN, revents: 0 };
    let num_fds = 1;
    let poll_result = unsafe {
      poll(&mut pollfd, num_fds, timeout_ms as c_int)
    };
    if poll_result < 0      { panic!("Unable to poll stdin."); }
    else if poll_result > 0 { PollResult::Ready }
    else                    { PollResult::Timeout }
  }
}

fn input_loop(kill_rx: Receiver<()>, died_tx: Sender<()>,
              key_tx: Sender<keymap::Key>, fd: libc::c_int) {
  let is_alive = || kill_rx.try_recv() == Err(TryRecvError::Empty);
  let mut tk = termkey::TermKey::new(fd, termkey::c::TERMKEY_FLAG_CTRLC);

  while is_alive() {
    // check for available input
    let poll_timeout_ms = 10;
    if libc_poll::poll_fd(fd, poll_timeout_ms) == libc_poll::PollResult::Ready {
      // tell termkey that there's input available
      tk.advisereadable();
    }

    // empty the fd, translating and sending key events
    loop {
      match tk.getkey() {
        TermKeyResult::None_      => break,  // got nothing, done here
        TermKeyResult::Eof        =>
          panic!("stdin closed, you're on your own."),
        TermKeyResult::Error{err} =>
          panic!("termkey::geykey failed with error code {}", err),
        TermKeyResult::Key(key)   => translate_key(key),
        TermKeyResult::Again      =>
          // There's input available, but not enough to make a key event. Likely
          // escape has been pushed, which we want to force out and interpret as
          // a key on its own, otherwise oops.
          match tk.getkey_force() {
            TermKeyResult::Key(key)   => translate_key(key),
            TermKeyResult::Eof        =>
              panic!("stdin closed, you're on your own."),
            TermKeyResult::Error{err} =>
              panic!("termkey::geykey_force failed with error code {}", err),
            _                         => unreachable!(),
          },
      }.map(|key| key_tx.send(key));
    }
  }

  died_tx.send(()).unwrap();
}

fn translate_key(key: TermKeyEvent) -> Option<keymap::Key> {
  match key {
    TermKeyEvent::FunctionEvent{num, mods}                =>
      Some(keymap::Key::Fn{num: num, mods: translate_mods(mods)}),
    TermKeyEvent::KeySymEvent{sym, mods}                  =>
      Some(keymap::Key::Sym{
        sym: translate_sym(sym), mods: translate_mods(mods)}),
    TermKeyEvent::UnicodeEvent{codepoint, mods, utf8:_}   =>
      Some(keymap::Key::Unicode{
        codepoint: codepoint, mods: translate_mods(mods)}),
    _                                                     =>
      None,
  }
}

fn translate_sym(sym: TermKeySym) -> keymap::KeySym {
  match sym {
    TermKeySym::TERMKEY_SYM_UNKNOWN   => keymap::KeySym::Unknown,
    TermKeySym::TERMKEY_SYM_NONE      => keymap::KeySym::None,
    TermKeySym::TERMKEY_SYM_BACKSPACE => keymap::KeySym::Backspace,
    TermKeySym::TERMKEY_SYM_TAB       => keymap::KeySym::Tab,
    TermKeySym::TERMKEY_SYM_ENTER     => keymap::KeySym::Enter,
    TermKeySym::TERMKEY_SYM_ESCAPE    => keymap::KeySym::Escape,
    TermKeySym::TERMKEY_SYM_SPACE     => keymap::KeySym::Space,
    TermKeySym::TERMKEY_SYM_DEL       => keymap::KeySym::Del,
    TermKeySym::TERMKEY_SYM_UP        => keymap::KeySym::Up,
    TermKeySym::TERMKEY_SYM_DOWN      => keymap::KeySym::Down,
    TermKeySym::TERMKEY_SYM_LEFT      => keymap::KeySym::Left,
    TermKeySym::TERMKEY_SYM_RIGHT     => keymap::KeySym::Right,
    TermKeySym::TERMKEY_SYM_BEGIN     => keymap::KeySym::Begin,
    TermKeySym::TERMKEY_SYM_FIND      => keymap::KeySym::Find,
    TermKeySym::TERMKEY_SYM_INSERT    => keymap::KeySym::Insert,
    TermKeySym::TERMKEY_SYM_DELETE    => keymap::KeySym::Delete,
    TermKeySym::TERMKEY_SYM_SELECT    => keymap::KeySym::Select,
    TermKeySym::TERMKEY_SYM_PAGEUP    => keymap::KeySym::Pageup,
    TermKeySym::TERMKEY_SYM_PAGEDOWN  => keymap::KeySym::Pagedown,
    TermKeySym::TERMKEY_SYM_HOME      => keymap::KeySym::Home,
    TermKeySym::TERMKEY_SYM_END       => keymap::KeySym::End,
    TermKeySym::TERMKEY_SYM_CANCEL    => keymap::KeySym::Cancel,
    TermKeySym::TERMKEY_SYM_CLEAR     => keymap::KeySym::Clear,
    TermKeySym::TERMKEY_SYM_CLOSE     => keymap::KeySym::Close,
    TermKeySym::TERMKEY_SYM_COMMAND   => keymap::KeySym::Command,
    TermKeySym::TERMKEY_SYM_COPY      => keymap::KeySym::Copy,
    TermKeySym::TERMKEY_SYM_EXIT      => keymap::KeySym::Exit,
    TermKeySym::TERMKEY_SYM_HELP      => keymap::KeySym::Help,
    TermKeySym::TERMKEY_SYM_MARK      => keymap::KeySym::Mark,
    TermKeySym::TERMKEY_SYM_MESSAGE   => keymap::KeySym::Message,
    TermKeySym::TERMKEY_SYM_MOVE      => keymap::KeySym::Move,
    TermKeySym::TERMKEY_SYM_OPEN      => keymap::KeySym::Open,
    TermKeySym::TERMKEY_SYM_OPTIONS   => keymap::KeySym::Options,
    TermKeySym::TERMKEY_SYM_PRINT     => keymap::KeySym::Print,
    TermKeySym::TERMKEY_SYM_REDO      => keymap::KeySym::Redo,
    TermKeySym::TERMKEY_SYM_REFERENCE => keymap::KeySym::Reference,
    TermKeySym::TERMKEY_SYM_REFRESH   => keymap::KeySym::Refresh,
    TermKeySym::TERMKEY_SYM_REPLACE   => keymap::KeySym::Replace,
    TermKeySym::TERMKEY_SYM_RESTART   => keymap::KeySym::Restart,
    TermKeySym::TERMKEY_SYM_RESUME    => keymap::KeySym::Resume,
    TermKeySym::TERMKEY_SYM_SAVE      => keymap::KeySym::Save,
    TermKeySym::TERMKEY_SYM_SUSPEND   => keymap::KeySym::Suspend,
    TermKeySym::TERMKEY_SYM_UNDO      => keymap::KeySym::Undo,
    TermKeySym::TERMKEY_SYM_KP0       => keymap::KeySym::KP0,
    TermKeySym::TERMKEY_SYM_KP1       => keymap::KeySym::KP1,
    TermKeySym::TERMKEY_SYM_KP2       => keymap::KeySym::KP2,
    TermKeySym::TERMKEY_SYM_KP3       => keymap::KeySym::KP3,
    TermKeySym::TERMKEY_SYM_KP4       => keymap::KeySym::KP4,
    TermKeySym::TERMKEY_SYM_KP5       => keymap::KeySym::KP5,
    TermKeySym::TERMKEY_SYM_KP6       => keymap::KeySym::KP6,
    TermKeySym::TERMKEY_SYM_KP7       => keymap::KeySym::KP7,
    TermKeySym::TERMKEY_SYM_KP8       => keymap::KeySym::KP8,
    TermKeySym::TERMKEY_SYM_KP9       => keymap::KeySym::KP9,
    TermKeySym::TERMKEY_SYM_KPENTER   => keymap::KeySym::KPEnter,
    TermKeySym::TERMKEY_SYM_KPPLUS    => keymap::KeySym::KPPlus,
    TermKeySym::TERMKEY_SYM_KPMINUS   => keymap::KeySym::KPMinus,
    TermKeySym::TERMKEY_SYM_KPMULT    => keymap::KeySym::KPMult,
    TermKeySym::TERMKEY_SYM_KPDIV     => keymap::KeySym::KPDiv,
    TermKeySym::TERMKEY_SYM_KPCOMMA   => keymap::KeySym::KPComma,
    TermKeySym::TERMKEY_SYM_KPPERIOD  => keymap::KeySym::KPPeriod,
    TermKeySym::TERMKEY_SYM_KPEQUALS  => keymap::KeySym::KPEquals,
    TermKeySym::TERMKEY_N_SYMS        => keymap::KeySym::NSyms,
  }
}

fn translate_mods(mods: termkey::c::X_TermKey_KeyMod) -> keymap::KeyMod {
  let mut ret = keymap::MOD_NONE;
  if mods.contains(termkey::c::TERMKEY_KEYMOD_SHIFT) {
    ret.insert(keymap::MOD_SHIFT);
  }
  if mods.contains(termkey::c::TERMKEY_KEYMOD_ALT) {
    ret.insert(keymap::MOD_ALT);
  }
  if mods.contains(termkey::c::TERMKEY_KEYMOD_CTRL) {
    ret.insert(keymap::MOD_CTRL);
  }
  return ret;
}

#[cfg(test)]
mod test {
  extern crate time;

  use super::libc;
  use std::mem;
  use std::sync::mpsc::{channel, Sender};
  use std::thread;
  use std::time::duration::Duration;

  use keymap;

  // Simulates stdin by writing bytes to a pipe, then listens for the key
  // outputs and matches with expectations.
  #[test]
  fn test_input() {
    // pairs of input bytes on "stdin" and corresponding expected key output
    let input_output_pairs = vec!(
      (vec!(0x61),
        keymap::Key::Unicode{codepoint: 'a', mods: keymap::MOD_NONE}),
      (vec!(0x1B, 0x61),
        keymap::Key::Unicode{codepoint: 'a', mods: keymap::MOD_ALT}),
      (vec!(0x1B),
        keymap::Key::Sym{sym: keymap::KeySym::Escape, mods: keymap::MOD_NONE}),
      (vec!(0x61),
        keymap::Key::Unicode{codepoint: 'a', mods: keymap::MOD_NONE}),
      (vec!(0x03),
        keymap::Key::Unicode{codepoint: 'c', mods: keymap::MOD_CTRL}),
      (vec!(0x1B, 0x5B, 0x41),
        keymap::Key::Sym{sym: keymap::KeySym::Up, mods: keymap::MOD_NONE}),
      (vec!(0x1B, 0x4F, 0x53),
        keymap::Key::Fn{num: 4, mods: keymap::MOD_NONE}),
      (vec!(0xE3, 0x81, 0x82),
        keymap::Key::Unicode{codepoint: 'あ', mods: keymap::MOD_NONE}),
    );

    let inputs: Vec<Vec<u8>> =
      input_output_pairs.iter().map(|&(ref input, _)| input.clone()).collect();
    let outputs: Vec<keymap::Key> =
      input_output_pairs.iter().map(|&(_, output)| output).collect();

    // set up communication channels
    let (key_tx, key_rx) = channel();
    let (reader_fd, writer_fd) = unsafe {
      let mut fds = [0; 2];
      if libc::pipe(fds.as_mut_ptr()) != 0 { panic!("Failed to create pipe"); }
      (fds[0], fds[1])
    };

    // make sure we quit in an orderly fashion even at failure
    let (close_writer_tx, close_writer_rx) = channel();
    struct PipeKiller { close_writer_tx: Sender<()>, reader_fd: libc::c_int }
    impl Drop for PipeKiller {
      fn drop(&mut self) {
        unsafe { libc::close(self.reader_fd); }
        self.close_writer_tx.send(()).unwrap();
      }
    }
    let _pipe_killer =
      PipeKiller { close_writer_tx: close_writer_tx, reader_fd: reader_fd };

    // start input listener
    let _term_input = super::start_on_fd(reader_fd, key_tx);

    // simulate keyboard input
    thread::spawn(move || {
      for input in inputs.iter() {
        unsafe {
          let buffer = mem::transmute(&input[0]);
          let count = input.len() as libc::size_t;
          libc::write(writer_fd, buffer, count);
        }

        // give termkey a chance to parse escape as a standalone key
        thread::sleep(Duration::milliseconds(1));
      }
      // keep the pipe alive until we're finished with it
      close_writer_rx.recv().unwrap();
      unsafe { libc::close(writer_fd); }
    });

    // receive key outputs and match with expectations
    let timeout_at = time::get_time() + Duration::milliseconds(100);
    for output in outputs.iter() {
      // just keep looping until the key arrives
      loop {
        match key_rx.try_recv() {
          Ok(key) => { assert_eq!(key, *output); break; }
          _       => (),
        }
        let time_now = time::get_time();
        if time_now > timeout_at { panic!("Timeout waiting for key event."); }
      }
    }
  }
}
<commit_msg>Avoid needless spinning in input test<commit_after>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

extern crate libc;
extern crate termkey;

use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::thread;

use self::termkey::{TermKeyEvent, TermKeyResult};
use self::termkey::c::TermKeySym;

use keymap;

#[cfg(not(test))]
const STDIN_FILENO: libc::c_int = 0;

/*
 * TermInput is returned when starting listening for key events on a file
 * descriptor. It controls the life time of the terminal input loop. When the
 * TermInput is dropped, the terminal input loop will finish.
 */
pub struct TermInput {
  kill_tx: Sender<()>,
  died_rx: Receiver<()>,
}

impl Drop for TermInput {
  fn drop(&mut self) {
    self.kill_tx.send(()).unwrap();
    self.died_rx.recv().unwrap();
  }
}

// start listening for terminal input on stdin
#[cfg(not(test))]
pub fn start(key_tx: Sender<keymap::Key>) -> TermInput {
  start_on_fd(STDIN_FILENO, key_tx)
}

// start listening for terminal input on the specified file descriptor
pub fn start_on_fd(fd: libc::c_int, key_tx: Sender<keymap::Key>) -> TermInput {
  let (kill_tx, kill_rx) = channel();
  let (died_tx, died_rx) = channel();
  thread::spawn(move || { input_loop(kill_rx, died_tx, key_tx, fd); });
  TermInput { kill_tx: kill_tx, died_rx: died_rx }
}

/*
 * Helper module for detecting available bytes on the file descriptor being
 * listened to.
 */
mod libc_poll {
  use super::libc::{c_int, c_long, c_short};

  #[repr(C)]
  struct Pollfd {
    fd: c_int,
    events: c_short,
    revents: c_short
  }

  extern {
    fn poll(fds: *mut Pollfd, nfds: c_long, timeout: c_int) -> c_int;
  }

  #[derive(PartialEq)]
  pub enum PollResult {
    Ready,
    Timeout,
  }

  pub fn poll_fd(fd: c_int, timeout_ms: int) -> PollResult {
    const POLLIN: c_short = 1;
    let mut pollfd = Pollfd { fd: fd, events: POLLIN, revents: 0 };
    let num_fds = 1;
    let poll_result = unsafe {
      poll(&mut pollfd, num_fds, timeout_ms as c_int)
    };
    if poll_result < 0      { panic!("Unable to poll stdin."); }
    else if poll_result > 0 { PollResult::Ready }
    else                    { PollResult::Timeout }
  }
}

fn input_loop(kill_rx: Receiver<()>, died_tx: Sender<()>,
              key_tx: Sender<keymap::Key>, fd: libc::c_int) {
  let is_alive = || kill_rx.try_recv() == Err(TryRecvError::Empty);
  let mut tk = termkey::TermKey::new(fd, termkey::c::TERMKEY_FLAG_CTRLC);

  while is_alive() {
    // check for available input
    let poll_timeout_ms = 10;
    if libc_poll::poll_fd(fd, poll_timeout_ms) == libc_poll::PollResult::Ready {
      // tell termkey that there's input available
      tk.advisereadable();
    }

    // empty the fd, translating and sending key events
    loop {
      match tk.getkey() {
        TermKeyResult::None_      => break,  // got nothing, done here
        TermKeyResult::Eof        =>
          panic!("stdin closed, you're on your own."),
        TermKeyResult::Error{err} =>
          panic!("termkey::geykey failed with error code {}", err),
        TermKeyResult::Key(key)   => translate_key(key),
        TermKeyResult::Again      =>
          // There's input available, but not enough to make a key event. Likely
          // escape has been pushed, which we want to force out and interpret as
          // a key on its own, otherwise oops.
          match tk.getkey_force() {
            TermKeyResult::Key(key)   => translate_key(key),
            TermKeyResult::Eof        =>
              panic!("stdin closed, you're on your own."),
            TermKeyResult::Error{err} =>
              panic!("termkey::geykey_force failed with error code {}", err),
            _                         => unreachable!(),
          },
      }.map(|key| key_tx.send(key));
    }
  }

  died_tx.send(()).unwrap();
}

fn translate_key(key: TermKeyEvent) -> Option<keymap::Key> {
  match key {
    TermKeyEvent::FunctionEvent{num, mods}                =>
      Some(keymap::Key::Fn{num: num, mods: translate_mods(mods)}),
    TermKeyEvent::KeySymEvent{sym, mods}                  =>
      Some(keymap::Key::Sym{
        sym: translate_sym(sym), mods: translate_mods(mods)}),
    TermKeyEvent::UnicodeEvent{codepoint, mods, utf8:_}   =>
      Some(keymap::Key::Unicode{
        codepoint: codepoint, mods: translate_mods(mods)}),
    _                                                     =>
      None,
  }
}

fn translate_sym(sym: TermKeySym) -> keymap::KeySym {
  match sym {
    TermKeySym::TERMKEY_SYM_UNKNOWN   => keymap::KeySym::Unknown,
    TermKeySym::TERMKEY_SYM_NONE      => keymap::KeySym::None,
    TermKeySym::TERMKEY_SYM_BACKSPACE => keymap::KeySym::Backspace,
    TermKeySym::TERMKEY_SYM_TAB       => keymap::KeySym::Tab,
    TermKeySym::TERMKEY_SYM_ENTER     => keymap::KeySym::Enter,
    TermKeySym::TERMKEY_SYM_ESCAPE    => keymap::KeySym::Escape,
    TermKeySym::TERMKEY_SYM_SPACE     => keymap::KeySym::Space,
    TermKeySym::TERMKEY_SYM_DEL       => keymap::KeySym::Del,
    TermKeySym::TERMKEY_SYM_UP        => keymap::KeySym::Up,
    TermKeySym::TERMKEY_SYM_DOWN      => keymap::KeySym::Down,
    TermKeySym::TERMKEY_SYM_LEFT      => keymap::KeySym::Left,
    TermKeySym::TERMKEY_SYM_RIGHT     => keymap::KeySym::Right,
    TermKeySym::TERMKEY_SYM_BEGIN     => keymap::KeySym::Begin,
    TermKeySym::TERMKEY_SYM_FIND      => keymap::KeySym::Find,
    TermKeySym::TERMKEY_SYM_INSERT    => keymap::KeySym::Insert,
    TermKeySym::TERMKEY_SYM_DELETE    => keymap::KeySym::Delete,
    TermKeySym::TERMKEY_SYM_SELECT    => keymap::KeySym::Select,
    TermKeySym::TERMKEY_SYM_PAGEUP    => keymap::KeySym::Pageup,
    TermKeySym::TERMKEY_SYM_PAGEDOWN  => keymap::KeySym::Pagedown,
    TermKeySym::TERMKEY_SYM_HOME      => keymap::KeySym::Home,
    TermKeySym::TERMKEY_SYM_END       => keymap::KeySym::End,
    TermKeySym::TERMKEY_SYM_CANCEL    => keymap::KeySym::Cancel,
    TermKeySym::TERMKEY_SYM_CLEAR     => keymap::KeySym::Clear,
    TermKeySym::TERMKEY_SYM_CLOSE     => keymap::KeySym::Close,
    TermKeySym::TERMKEY_SYM_COMMAND   => keymap::KeySym::Command,
    TermKeySym::TERMKEY_SYM_COPY      => keymap::KeySym::Copy,
    TermKeySym::TERMKEY_SYM_EXIT      => keymap::KeySym::Exit,
    TermKeySym::TERMKEY_SYM_HELP      => keymap::KeySym::Help,
    TermKeySym::TERMKEY_SYM_MARK      => keymap::KeySym::Mark,
    TermKeySym::TERMKEY_SYM_MESSAGE   => keymap::KeySym::Message,
    TermKeySym::TERMKEY_SYM_MOVE      => keymap::KeySym::Move,
    TermKeySym::TERMKEY_SYM_OPEN      => keymap::KeySym::Open,
    TermKeySym::TERMKEY_SYM_OPTIONS   => keymap::KeySym::Options,
    TermKeySym::TERMKEY_SYM_PRINT     => keymap::KeySym::Print,
    TermKeySym::TERMKEY_SYM_REDO      => keymap::KeySym::Redo,
    TermKeySym::TERMKEY_SYM_REFERENCE => keymap::KeySym::Reference,
    TermKeySym::TERMKEY_SYM_REFRESH   => keymap::KeySym::Refresh,
    TermKeySym::TERMKEY_SYM_REPLACE   => keymap::KeySym::Replace,
    TermKeySym::TERMKEY_SYM_RESTART   => keymap::KeySym::Restart,
    TermKeySym::TERMKEY_SYM_RESUME    => keymap::KeySym::Resume,
    TermKeySym::TERMKEY_SYM_SAVE      => keymap::KeySym::Save,
    TermKeySym::TERMKEY_SYM_SUSPEND   => keymap::KeySym::Suspend,
    TermKeySym::TERMKEY_SYM_UNDO      => keymap::KeySym::Undo,
    TermKeySym::TERMKEY_SYM_KP0       => keymap::KeySym::KP0,
    TermKeySym::TERMKEY_SYM_KP1       => keymap::KeySym::KP1,
    TermKeySym::TERMKEY_SYM_KP2       => keymap::KeySym::KP2,
    TermKeySym::TERMKEY_SYM_KP3       => keymap::KeySym::KP3,
    TermKeySym::TERMKEY_SYM_KP4       => keymap::KeySym::KP4,
    TermKeySym::TERMKEY_SYM_KP5       => keymap::KeySym::KP5,
    TermKeySym::TERMKEY_SYM_KP6       => keymap::KeySym::KP6,
    TermKeySym::TERMKEY_SYM_KP7       => keymap::KeySym::KP7,
    TermKeySym::TERMKEY_SYM_KP8       => keymap::KeySym::KP8,
    TermKeySym::TERMKEY_SYM_KP9       => keymap::KeySym::KP9,
    TermKeySym::TERMKEY_SYM_KPENTER   => keymap::KeySym::KPEnter,
    TermKeySym::TERMKEY_SYM_KPPLUS    => keymap::KeySym::KPPlus,
    TermKeySym::TERMKEY_SYM_KPMINUS   => keymap::KeySym::KPMinus,
    TermKeySym::TERMKEY_SYM_KPMULT    => keymap::KeySym::KPMult,
    TermKeySym::TERMKEY_SYM_KPDIV     => keymap::KeySym::KPDiv,
    TermKeySym::TERMKEY_SYM_KPCOMMA   => keymap::KeySym::KPComma,
    TermKeySym::TERMKEY_SYM_KPPERIOD  => keymap::KeySym::KPPeriod,
    TermKeySym::TERMKEY_SYM_KPEQUALS  => keymap::KeySym::KPEquals,
    TermKeySym::TERMKEY_N_SYMS        => keymap::KeySym::NSyms,
  }
}

fn translate_mods(mods: termkey::c::X_TermKey_KeyMod) -> keymap::KeyMod {
  let mut ret = keymap::MOD_NONE;
  if mods.contains(termkey::c::TERMKEY_KEYMOD_SHIFT) {
    ret.insert(keymap::MOD_SHIFT);
  }
  if mods.contains(termkey::c::TERMKEY_KEYMOD_ALT) {
    ret.insert(keymap::MOD_ALT);
  }
  if mods.contains(termkey::c::TERMKEY_KEYMOD_CTRL) {
    ret.insert(keymap::MOD_CTRL);
  }
  return ret;
}

#[cfg(test)]
mod test {
  extern crate time;

  use super::libc;
  use std::mem;
  use std::sync::mpsc::{channel, Sender};
  use std::thread;
  use std::time::duration::Duration;

  use keymap;

  // Simulates stdin by writing bytes to a pipe, then listens for the key
  // outputs and matches with expectations.
  #[test]
  fn test_input() {
    // pairs of input bytes on "stdin" and corresponding expected key output
    let input_output_pairs = vec!(
      (vec!(0x61),
        keymap::Key::Unicode{codepoint: 'a', mods: keymap::MOD_NONE}),
      (vec!(0x1B, 0x61),
        keymap::Key::Unicode{codepoint: 'a', mods: keymap::MOD_ALT}),
      (vec!(0x1B),
        keymap::Key::Sym{sym: keymap::KeySym::Escape, mods: keymap::MOD_NONE}),
      (vec!(0x61),
        keymap::Key::Unicode{codepoint: 'a', mods: keymap::MOD_NONE}),
      (vec!(0x03),
        keymap::Key::Unicode{codepoint: 'c', mods: keymap::MOD_CTRL}),
      (vec!(0x1B, 0x5B, 0x41),
        keymap::Key::Sym{sym: keymap::KeySym::Up, mods: keymap::MOD_NONE}),
      (vec!(0x1B, 0x4F, 0x53),
        keymap::Key::Fn{num: 4, mods: keymap::MOD_NONE}),
      (vec!(0xE3, 0x81, 0x82),
        keymap::Key::Unicode{codepoint: 'あ', mods: keymap::MOD_NONE}),
    );

    let inputs: Vec<Vec<u8>> =
      input_output_pairs.iter().map(|&(ref input, _)| input.clone()).collect();
    let outputs: Vec<keymap::Key> =
      input_output_pairs.iter().map(|&(_, output)| output).collect();

    // set up communication channels
    let (key_tx, key_rx) = channel();
    let (reader_fd, writer_fd) = unsafe {
      let mut fds = [0; 2];
      if libc::pipe(fds.as_mut_ptr()) != 0 { panic!("Failed to create pipe"); }
      (fds[0], fds[1])
    };

    // make sure we quit in an orderly fashion even at failure
    let (close_writer_tx, close_writer_rx) = channel();
    struct PipeKiller { close_writer_tx: Sender<()>, reader_fd: libc::c_int }
    impl Drop for PipeKiller {
      fn drop(&mut self) {
        unsafe { libc::close(self.reader_fd); }
        self.close_writer_tx.send(()).unwrap();
      }
    }
    let _pipe_killer =
      PipeKiller { close_writer_tx: close_writer_tx, reader_fd: reader_fd };

    // start input listener
    let _term_input = super::start_on_fd(reader_fd, key_tx);

    // simulate keyboard input
    thread::spawn(move || {
      for input in inputs.iter() {
        unsafe {
          let buffer = mem::transmute(&input[0]);
          let count = input.len() as libc::size_t;
          libc::write(writer_fd, buffer, count);
        }

        // give termkey a chance to parse escape as a standalone key
        thread::sleep(Duration::milliseconds(1));
      }
      // keep the pipe alive until we're finished with it
      close_writer_rx.recv().unwrap();
      unsafe { libc::close(writer_fd); }
    });

    // receive key outputs and match with expectations
    let (timeout_tx, timeout_rx) = channel();
    thread::spawn(move || {
      thread::sleep(Duration::milliseconds(100)); timeout_tx.send(()).ok();
    });
    for output in outputs.iter() {
      select!(
        key = key_rx.recv()   => { assert_eq!(key.unwrap(), *output); },
        _ = timeout_rx.recv() => { panic!("Timeout waiting for key event."); }
      );
    }
  }
}
<|endoftext|>


<commit_before>fn main() {

    let x: i32 = 5;
    {
        let y: i32 = 3;
        println!("({},{})",x,y)
    }

    //Invalid, y is out of scope
    //println!("({},{})",x,y)

    let y: i32 = 10;
    print_number(x);

    print_sum(x,y);

    println!("x+1={}",add_one(x));

    println!("Finished!");
}

fn print_number(x: i32){
        println!("x is {}",x)
}

fn print_sum(x: i32, y: i32){
        println!("x+y is {}",y+x)
}

fn add_one(x: i32) -> i32 {
    x + 1
}
<commit_msg>Sections<commit_after>fn main() {

    //Variable bindings

    let x: i32 = 5;
    {
        let y: i32 = 3;
        println!("({},{})",x,y)
    }

    //Invalid, y is out of scope
    //println!("({},{})",x,y)

    let y: i32 = 10;
    print_number(x);

    print_sum(x,y);

    println!("x+1={}",add_one(x));

    //Expressions and Statements

    //Invalid: let x = (let y = 5);

    println!("Finished!");
}

fn print_number(x: i32){
        println!("x is {}",x)
}

fn print_sum(x: i32, y: i32){
        println!("x+y is {}",y+x)
}

fn add_one(x: i32) -> i32 {
    x + 1
}
<|endoftext|>


<commit_before>use clang::{Entity, EntityKind, EntityVisitResult, TranslationUnit};
use std::vec::Vec;
use std::string::String;
use std::option::Option;

#[derive(Serialize, Deserialize, Debug)]
pub struct Model {
    interfaces: Vec<Interface>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Interface {
    name: String,
    namespaces: Vec<String>,
    methods: Vec<Method>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Method {
    name: String,
    return_type: String,
    arguments: Vec<Argument>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Argument {
    name: Option<String>,
    argument_type: String,
}

impl Model {
    pub fn new(tu: &TranslationUnit) -> Model {
        let mut model = Model { interfaces: vec![] };
        {
            let visitor = |node: Entity, parent: Entity| build_model(&mut model, node, parent);
            tu.get_entity().visit_children(visitor);
        }
        model
    }
}

fn build_model(model: &mut Model, node: Entity, parent: Entity) -> EntityVisitResult {
    if !node.is_in_main_file() {
        return EntityVisitResult::Continue;
    }

    if !is_interface(node) {
        return EntityVisitResult::Continue;
    }

    if node.get_kind() == EntityKind::StructDecl {
        model.interfaces.push(Interface {
            name: node.get_name().unwrap_or("unknown".to_string()),
            namespaces: parse_namespaces(parent),
            methods: parse_pure_virtual_methods(node),
        });
        EntityVisitResult::Continue
    } else {
        EntityVisitResult::Recurse
    }
}

fn parse_namespaces(node: Entity) -> Vec<String> {
    let mut pointer = node;
    let mut namespace_list = vec![];
    while pointer.get_kind() == EntityKind::Namespace {
        namespace_list.push(pointer.get_name().unwrap());
        match pointer.get_lexical_parent() {
            Some(n) => pointer = n,
            None => break,
        }
    }
    namespace_list.reverse();
    namespace_list
}

fn parse_pure_virtual_methods(node: Entity) -> Vec<Method> {
    node.get_children()
        .into_iter()
        .filter(|method| method.is_pure_virtual_method())
        .map(parse_method)
        .collect::<Vec<_>>()
}

fn parse_method(node: Entity) -> Method {
    Method {
        name: node.get_name().unwrap(),
        return_type: "void".to_string(),
        arguments: parse_arguments(node),
    }
}

fn parse_arguments(node: Entity) -> Vec<Argument> {
    node.get_arguments().map_or(vec![],
                                |t| t.into_iter().map(parse_argument).collect::<Vec<_>>())
}

fn parse_argument(t: Entity) -> Argument {
    Argument {
        name: t.get_name(),
        argument_type: t.get_type().unwrap().get_display_name(),
    }
}

fn is_interface(node: Entity) -> bool {
    node.get_children().into_iter().any(|method| {
        method.get_kind() == EntityKind::Destructor || !method.is_pure_virtual_method()
    })
}
<commit_msg>Fix bug with false positive inteface detection<commit_after>use clang::{Entity, EntityKind, EntityVisitResult, TranslationUnit};
use std::vec::Vec;
use std::string::String;
use std::option::Option;

#[derive(Serialize, Deserialize, Debug)]
pub struct Model {
    interfaces: Vec<Interface>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Interface {
    name: String,
    namespaces: Vec<String>,
    methods: Vec<Method>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Method {
    name: String,
    return_type: String,
    arguments: Vec<Argument>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Argument {
    name: Option<String>,
    argument_type: String,
}

impl Model {
    pub fn new(tu: &TranslationUnit) -> Model {
        let mut model = Model { interfaces: vec![] };
        {
            let visitor = |node: Entity, parent: Entity| build_model(&mut model, node, parent);
            tu.get_entity().visit_children(visitor);
        }
        model
    }
}

fn build_model(model: &mut Model, node: Entity, parent: Entity) -> EntityVisitResult {
    if !node.is_in_main_file() {
        return EntityVisitResult::Continue;
    }

    if !is_interface(node) {
        return EntityVisitResult::Continue;
    }

    if node.get_kind() == EntityKind::StructDecl {
        model.interfaces.push(Interface {
            name: node.get_name().unwrap_or("unknown".to_string()),
            namespaces: parse_namespaces(parent),
            methods: parse_pure_virtual_methods(node),
        });
        EntityVisitResult::Continue
    } else {
        EntityVisitResult::Recurse
    }
}

fn parse_namespaces(node: Entity) -> Vec<String> {
    let mut pointer = node;
    let mut namespace_list = vec![];
    while pointer.get_kind() == EntityKind::Namespace {
        namespace_list.push(pointer.get_name().unwrap());
        match pointer.get_lexical_parent() {
            Some(n) => pointer = n,
            None => break,
        }
    }
    namespace_list.reverse();
    namespace_list
}

fn parse_pure_virtual_methods(node: Entity) -> Vec<Method> {
    node.get_children()
        .into_iter()
        .filter(|method| method.is_pure_virtual_method())
        .map(parse_method)
        .collect::<Vec<_>>()
}

fn parse_method(node: Entity) -> Method {
    Method {
        name: node.get_name().unwrap(),
        return_type: "void".to_string(),
        arguments: parse_arguments(node),
    }
}

fn parse_arguments(node: Entity) -> Vec<Argument> {
    node.get_arguments().map_or(vec![],
                                |t| t.into_iter().map(parse_argument).collect::<Vec<_>>())
}

fn parse_argument(t: Entity) -> Argument {
    Argument {
        name: t.get_name(),
        argument_type: t.get_type().unwrap().get_display_name(),
    }
}

fn is_interface(node: Entity) -> bool {
    node.get_children().into_iter().all(|method| {
        method.get_kind() == EntityKind::Destructor || !method.is_pure_virtual_method()
    })
}
<|endoftext|>


<commit_before>use address::{Address, LENGTH};
use network;
use node;
use num::bigint::ToBigUint;
use num;
use std::thread;
use std;

pub fn start_multiple(port_start: u16, port_end: u16, router_host: Option<&str>) {
    let min = 0.to_biguint().unwrap();
    let max = num::pow(2.to_biguint().unwrap(), LENGTH);

    println!("Starting nodes {}..{}", port_start, port_end);

    for port in port_start..port_end {
        println!("-> {}", port);

        let routers: Vec<Box<node::Node>> = match router_host {
            Some(host) => {
                let router_node = Box::new(node::UdpNode::new(Address::null(), host));
                vec![router_node]
            }
            None => vec![]
        };

        let address = Address::random(&min, &max);
        let socket_address = ("127.0.0.1", port);
        let self_node = node::UdpNode::new(address, socket_address);
        let network = network::Network::new(self_node, socket_address, routers);
        network.run();
        thread::sleep(std::time::Duration::from_millis(200));
    }

    println!("All running :)");
    loop { thread::park(); }
}
<commit_msg>Run client in each network instance in multi-start<commit_after>use address::{Address, LENGTH};
use client;
use network;
use node;
use num::bigint::ToBigUint;
use num;
use std::thread;
use std;

pub fn start_multiple(port_start: u16, port_end: u16, router_host: Option<&str>) {
    let min = 0.to_biguint().unwrap();
    let max = num::pow(2.to_biguint().unwrap(), LENGTH);

    println!("Starting nodes {}..{}", port_start, port_end);

    for port in port_start..port_end {
        println!("-> {}", port);

        let routers: Vec<Box<node::Node>> = match router_host {
            Some(host) => {
                let router_node = Box::new(node::UdpNode::new(Address::null(), host));
                vec![router_node]
            }
            None => vec![]
        };

        let address = Address::random(&min, &max);
        let socket_address = ("127.0.0.1", port);
        let self_node = node::UdpNode::new(address, socket_address);
        let network = network::Network::new(self_node, socket_address, routers);
        let client = client::Client::new(address);
        thread::spawn(move || client.run(network));
        thread::sleep(std::time::Duration::from_millis(200));
    }

    println!("All running :)");
    loop { thread::park(); }
}
<|endoftext|>


<commit_before>use core::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};
use core::fmt;
use core::option::Option::{self, None, Some};
use core::default::Default;
use util::cpu_relax;

/// This type provides MUTual EXclusion based on spinning.
///
/// # Description
///
/// This structure behaves a lot like a normal Mutex. There are some differences:
///
/// - It may be used outside the runtime.
///   - A normal mutex will fail when used without the runtime, this will just lock
///   - When the runtime is present, it will call the deschedule function when appropriate
/// - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
///
/// When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
/// helpful. In other cases however, you are encouraged to use the locks from the standard
/// library.
///
/// # Simple example
///
/// ```
/// use spin;
/// let spin_mutex = spin::Mutex::new(0);
///
/// // Modify the data
/// {
///     let mut data = spin_mutex.lock();
///     *data = 2;
/// }
///
/// // Read the data
/// let answer =
/// {
///     let data = spin_mutex.lock();
///     *data
/// };
///
/// assert_eq!(answer, 2);
/// ```
///
/// # Thread-safety example
///
/// ```
/// use spin;
/// use std::sync::{Arc, Barrier};
///
/// let numthreads = 1000;
/// let spin_mutex = Arc::new(spin::Mutex::new(0));
///
/// // We use a barrier to ensure the readout happens after all writing
/// let barrier = Arc::new(Barrier::new(numthreads + 1));
///
/// for _ in (0..numthreads)
/// {
///     let my_barrier = barrier.clone();
///     let my_lock = spin_mutex.clone();
///     std::thread::spawn(move||
///     {
///         let mut guard = my_lock.lock();
///         *guard += 1;
///
///         // Release the lock to prevent a deadlock
///         drop(guard);
///         my_barrier.wait();
///     });
/// }
///
/// barrier.wait();
///
/// let answer = { *spin_mutex.lock() };
/// assert_eq!(answer, numthreads);
/// ```
pub struct Mutex<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct MutexGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Mutex<T> {}

impl<T> Mutex<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    ///
    /// May be used statically:
    ///
    /// ```
    /// #![feature(const_fn)]
    /// use spin;
    ///
    /// static MUTEX: spin::Mutex<()> = spin::Mutex::new(());
    ///
    /// fn demo() {
    ///     let lock = MUTEX.lock();
    ///     // do something with lock
    ///     drop(lock);
    /// }
    /// ```
    pub const fn new(user_data: T) -> Mutex<T>
    {
        Mutex
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            cpu_relax();
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spin::Mutex::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    ///     // The lock is implicitly dropped
    /// }
    ///
    /// ```
    pub fn lock(&self) -> MutexGuard<T>
    {
        self.obtain_lock();
        MutexGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns
    /// a guard within Some.
    fn try_lock(&self) -> Option<MutexGuard<T>>
    {
        if self.lock.compare_and_swap(false, true, Ordering::SeqCst) == false
        {
            Some(
                MutexGuard {
                    lock: &self.lock,
                    data: unsafe { &mut *self.data.get() },
                }
            )
        }
        else
        {
            None
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for Mutex<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match self.try_lock()
        {
            Some(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
            None => write!(f, "Mutex {{ <locked> }}"),
        }
    }
}

impl<T: Default> Default for Mutex<T> {
    fn default() -> Mutex<T> {
        Mutex::new(Default::default())
    }
}

impl<'a, T> Deref for MutexGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for MutexGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

impl<'a, T> Drop for MutexGuard<'a, T>
{
    /// The dropping of the MutexGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}

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

    #[test]
    fn try_lock() {
        let mutex = Mutex::new(42);

        // First lock succeeds
        let a = mutex.try_lock();
        assert!(a.is_some());

        // Additional lock failes
        let b = mutex.try_lock();
        assert!(b.is_none());

        // After dropping lock, it succeeds again
        ::core::mem::drop(a);
        let c = mutex.try_lock();
        assert!(c.is_some());
    }
}
<commit_msg>relax spinlock memory order<commit_after>use core::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};
use core::fmt;
use core::option::Option::{self, None, Some};
use core::default::Default;
use util::cpu_relax;

/// This type provides MUTual EXclusion based on spinning.
///
/// # Description
///
/// This structure behaves a lot like a normal Mutex. There are some differences:
///
/// - It may be used outside the runtime.
///   - A normal mutex will fail when used without the runtime, this will just lock
///   - When the runtime is present, it will call the deschedule function when appropriate
/// - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
///
/// When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
/// helpful. In other cases however, you are encouraged to use the locks from the standard
/// library.
///
/// # Simple example
///
/// ```
/// use spin;
/// let spin_mutex = spin::Mutex::new(0);
///
/// // Modify the data
/// {
///     let mut data = spin_mutex.lock();
///     *data = 2;
/// }
///
/// // Read the data
/// let answer =
/// {
///     let data = spin_mutex.lock();
///     *data
/// };
///
/// assert_eq!(answer, 2);
/// ```
///
/// # Thread-safety example
///
/// ```
/// use spin;
/// use std::sync::{Arc, Barrier};
///
/// let numthreads = 1000;
/// let spin_mutex = Arc::new(spin::Mutex::new(0));
///
/// // We use a barrier to ensure the readout happens after all writing
/// let barrier = Arc::new(Barrier::new(numthreads + 1));
///
/// for _ in (0..numthreads)
/// {
///     let my_barrier = barrier.clone();
///     let my_lock = spin_mutex.clone();
///     std::thread::spawn(move||
///     {
///         let mut guard = my_lock.lock();
///         *guard += 1;
///
///         // Release the lock to prevent a deadlock
///         drop(guard);
///         my_barrier.wait();
///     });
/// }
///
/// barrier.wait();
///
/// let answer = { *spin_mutex.lock() };
/// assert_eq!(answer, numthreads);
/// ```
pub struct Mutex<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct MutexGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Mutex<T> {}

impl<T> Mutex<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    ///
    /// May be used statically:
    ///
    /// ```
    /// #![feature(const_fn)]
    /// use spin;
    ///
    /// static MUTEX: spin::Mutex<()> = spin::Mutex::new(());
    ///
    /// fn demo() {
    ///     let lock = MUTEX.lock();
    ///     // do something with lock
    ///     drop(lock);
    /// }
    /// ```
    pub const fn new(user_data: T) -> Mutex<T>
    {
        Mutex
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false
        {
            cpu_relax();
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spin::Mutex::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    ///     // The lock is implicitly dropped
    /// }
    ///
    /// ```
    pub fn lock(&self) -> MutexGuard<T>
    {
        self.obtain_lock();
        MutexGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns
    /// a guard within Some.
    fn try_lock(&self) -> Option<MutexGuard<T>>
    {
        if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false
        {
            Some(
                MutexGuard {
                    lock: &self.lock,
                    data: unsafe { &mut *self.data.get() },
                }
            )
        }
        else
        {
            None
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for Mutex<T>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match self.try_lock()
        {
            Some(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
            None => write!(f, "Mutex {{ <locked> }}"),
        }
    }
}

impl<T: Default> Default for Mutex<T> {
    fn default() -> Mutex<T> {
        Mutex::new(Default::default())
    }
}

impl<'a, T> Deref for MutexGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for MutexGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

impl<'a, T> Drop for MutexGuard<'a, T>
{
    /// The dropping of the MutexGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::Release);
    }
}

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

    #[test]
    fn try_lock() {
        let mutex = Mutex::new(42);

        // First lock succeeds
        let a = mutex.try_lock();
        assert!(a.is_some());

        // Additional lock failes
        let b = mutex.try_lock();
        assert!(b.is_none());

        // After dropping lock, it succeeds again
        ::core::mem::drop(a);
        let c = mutex.try_lock();
        assert!(c.is_some());
    }
}
<|endoftext|>


<commit_before>use std;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io;

use tempdir::TempDir;

use pipeline::{CompileOptions, OutputType};
use ir;
use codegen;

fn get_writer(output_path: &Option<PathBuf>) -> io::Result<Box<std::io::Write>>{
    if let Some(ref output_path) = *output_path {
        Ok(Box::new(std::fs::File::create(output_path)?))
    } else {
        Ok(Box::new(std::io::stdout()))
    }
}

pub fn main_outer(tu: ir::TranslationUnit, input_path: &str, options: &CompileOptions) -> io::Result<()> {
    match options.output_type {
        OutputType::None => Ok(()),
        OutputType::LLVM => {
            let mut writer = get_writer(&options.output_path)?;
            codegen::llvm_gen::gen_translation_unit(&mut writer, tu)
        }
        OutputType::Run => {
            run_with_llvm(tu, input_path, options)
        }
    }
}

fn executable_name(path: &str) -> String {
    let file_name = Path::new(path).file_name().unwrap().to_str().unwrap();

    let mut name_parts: Vec<_> = file_name.split('.').collect();
    let parts_len = name_parts.len();
    if parts_len > 1 {
        name_parts.pop();
    }

    name_parts.join(".")
}

fn run_with_llvm(tu: ir::TranslationUnit, input_path: &str, options: &CompileOptions) -> io::Result<()> {
    let exec_name = executable_name(input_path);

    let tmp_dir = TempDir::new("elang-compiler")?;
    let llvm_path = tmp_dir.path().join(format!("{}.ll", exec_name));
    let obj_path = tmp_dir.path().join(format!("{}.o", exec_name));
    let exec_path = tmp_dir.path().join(exec_name);

    let mut llvm_file = File::create(&llvm_path)?;
    codegen::llvm_gen::gen_translation_unit(&mut llvm_file, tu).expect("error llvm gen");

    if options.opt {
        if !std::process::Command::new("opt")
            .arg("-O3")
            .arg("-S")
            .arg(llvm_path.to_str().unwrap())
            .arg("-o").arg(llvm_path.to_str().unwrap())
            .spawn()?
            .wait()?
            .success() {
            panic!("opt fail");
        }
    }

    if !std::process::Command::new("llc")
        .arg("-filetype=obj")
        .arg(llvm_path.to_str().unwrap())
        .arg("-o").arg(obj_path.to_str().unwrap())
        .spawn()?
        .wait()?
        .success() {
        panic!("llc fail");
    }

    if !std::process::Command::new("clang")
        .arg(obj_path.to_str().unwrap())
        .arg("-o").arg(exec_path.to_str().unwrap())
        .spawn()?
        .wait()?
        .success() {
        panic!("clang fail");
    }

    if !std::process::Command::new(exec_path)
        .spawn()?
        .wait()?
        .success() {
        panic!("exec fail");
    }

    Ok(())
}
<commit_msg>Better outer<commit_after>use std;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io;

use tempdir::TempDir;

use pipeline::{CompileOptions, OutputType};
use ir;
use codegen;

fn get_writer(output_path: &Option<PathBuf>) -> io::Result<Box<std::io::Write>> {
    if let Some(ref output_path) = *output_path {
        Ok(Box::new(std::fs::File::create(output_path)?))
    } else {
        Ok(Box::new(std::io::stdout()))
    }
}

pub fn main_outer(tu: ir::TranslationUnit,
                  input_path: &str,
                  options: &CompileOptions)
                  -> io::Result<()> {
    match options.output_type {
        OutputType::None => Ok(()),
        OutputType::LLVM => {
            let mut writer = get_writer(&options.output_path)?;
            codegen::llvm_gen::gen_translation_unit(&mut writer, tu)
        }
        OutputType::Run => run_with_llvm(tu, input_path, options),
    }
}

fn executable_name(path: &str) -> String {
    let file_name = Path::new(path).file_name().unwrap().to_str().unwrap();

    let mut name_parts: Vec<_> = file_name.split('.').collect();
    let parts_len = name_parts.len();
    if parts_len > 1 {
        name_parts.pop();
    }

    name_parts.join(".")
}

fn run_with_llvm(tu: ir::TranslationUnit,
                 input_path: &str,
                 options: &CompileOptions)
                 -> io::Result<()> {
    fn path_to_str(path: &PathBuf) -> &str {
        path.to_str().unwrap()
    }

    let exec_name = executable_name(input_path);

    let tmp_dir = TempDir::new("elang-compiler")?;
    let llvm_path = tmp_dir.path().join(format!("{}.ll", exec_name));
    let obj_path = tmp_dir.path().join(format!("{}.o", exec_name));
    let exec_path = tmp_dir.path().join(exec_name);

    let mut llvm_file = File::create(&llvm_path)?;
    codegen::llvm_gen::gen_translation_unit(&mut llvm_file, tu).expect("error llvm gen");

    if options.opt &&
       !run_command("opt",
                    &["-O3", "-S", path_to_str(&llvm_path), "-o", path_to_str(&llvm_path)])?
                .success() {
        panic!("opt fail");
    }

    if !run_command("llc",
                    &["-filetype=obj", path_to_str(&llvm_path), "-o", path_to_str(&obj_path)])?
                .success() {
        panic!("llc fail");
    }

    if !run_command("clang",
                    &[path_to_str(&obj_path), "-o", path_to_str(&exec_path)])?
                .success() {
        panic!("clang fail");
    }

    if !run_command(exec_path, &[])?.success() {
        panic!("exec fail");
    }

    Ok(())
}

fn run_command<S: AsRef<std::ffi::OsStr>>(ex: S, args: &[&str]) -> io::Result<std::process::ExitStatus> {
    std::process::Command::new(ex).args(args).status()
}
<|endoftext|>