<commit_before><commit_msg>move session to separate crate<commit_after>//! User sessions.
//!
//! Actix provides a general solution for session management. The
//! [**SessionStorage**](struct.SessionStorage.html)
//! middleware can be used with different backend types to store session
//! data in different backends.
//!
//! By default, only cookie session backend is implemented. Other
//! backend implementations can be added.
//!
//! [**CookieSessionBackend**](struct.CookieSessionBackend.html)
//! uses cookies as session storage. `CookieSessionBackend` creates sessions
//! which are limited to storing fewer than 4000 bytes of data, as the payload
//! must fit into a single cookie. An internal server error is generated if a
//! session contains more than 4000 bytes.
//!
//! A cookie may have a security policy of *signed* or *private*. Each has
//! a respective `CookieSessionBackend` constructor.
//!
//! A *signed* cookie may be viewed but not modified by the client. A *private*
//! cookie may neither be viewed nor modified by the client.
//!
//! The constructors take a key as an argument. This is the private key
//! for cookie session - when this value is changed, all session data is lost.
//!
//! In general, you create a `SessionStorage` middleware and initialize it
//! with specific backend implementation, such as a `CookieSessionBackend`.
//! To access session data,
//! [*HttpRequest::session()*](trait.RequestSession.html#tymethod.session)
//! must be used. This method returns a
//! [*Session*](struct.Session.html) object, which allows us to get or set
//! session data.
//!
//! ```rust
//! # extern crate actix_web;
//! # extern crate actix;
//! use actix_web::{server, App, HttpRequest, Result};
//! use actix_web::middleware::session::{RequestSession, SessionStorage, CookieSessionBackend};
//!
//! fn index(req: HttpRequest) -> Result<&'static str> {
//!     // access session data
//!     if let Some(count) = req.session().get::<i32>("counter")? {
//!         println!("SESSION value: {}", count);
//!         req.session().set("counter", count+1)?;
//!     } else {
//!         req.session().set("counter", 1)?;
//!     }
//!
//!     Ok("Welcome!")
//! }
//!
//! fn main() {
//!     actix::System::run(|| {
//!         server::new(
//!           || App::new().middleware(
//!               SessionStorage::new(          // <- create session middleware
//!                 CookieSessionBackend::signed(&[0; 32]) // <- create signed cookie session backend
//!                     .secure(false)
//!              )))
//!             .bind("127.0.0.1:59880").unwrap()
//!             .start();
//! #         actix::System::current().stop();
//!     });
//! }
//! ```
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::Arc;

use cookie::{Cookie, CookieJar, Key, SameSite};
use futures::future::{err as FutErr, ok as FutOk, FutureResult};
use futures::Future;
use http::header::{self, HeaderValue};
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json;
use serde_json::error::Error as JsonError;
use time::Duration;

use error::{Error, ResponseError, Result};
use handler::FromRequest;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::{Middleware, Response, Started};

/// The helper trait to obtain your session data from a request.
///
/// ```rust
/// use actix_web::middleware::session::RequestSession;
/// use actix_web::*;
///
/// fn index(mut req: HttpRequest) -> Result<&'static str> {
///     // access session data
///     if let Some(count) = req.session().get::<i32>("counter")? {
///         req.session().set("counter", count + 1)?;
///     } else {
///         req.session().set("counter", 1)?;
///     }
///
///     Ok("Welcome!")
/// }
/// # fn main() {}
/// ```
pub trait RequestSession {
    /// Get the session from the request
    fn session(&self) -> Session;
}

impl<S> RequestSession for HttpRequest<S> {
    fn session(&self) -> Session {
        if let Some(s_impl) = self.extensions().get::<Arc<SessionImplCell>>() {
            return Session(SessionInner::Session(Arc::clone(&s_impl)));
        }
        Session(SessionInner::None)
    }
}

/// The high-level interface you use to modify session data.
///
/// Session object could be obtained with
/// [`RequestSession::session`](trait.RequestSession.html#tymethod.session)
/// method. `RequestSession` trait is implemented for `HttpRequest`.
///
/// ```rust
/// use actix_web::middleware::session::RequestSession;
/// use actix_web::*;
///
/// fn index(mut req: HttpRequest) -> Result<&'static str> {
///     // access session data
///     if let Some(count) = req.session().get::<i32>("counter")? {
///         req.session().set("counter", count + 1)?;
///     } else {
///         req.session().set("counter", 1)?;
///     }
///
///     Ok("Welcome!")
/// }
/// # fn main() {}
/// ```
pub struct Session(SessionInner);

enum SessionInner {
    Session(Arc<SessionImplCell>),
    None,
}

impl Session {
    /// Get a `value` from the session.
    pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
        match self.0 {
            SessionInner::Session(ref sess) => {
                if let Some(s) = sess.as_ref().0.borrow().get(key) {
                    Ok(Some(serde_json::from_str(s)?))
                } else {
                    Ok(None)
                }
            }
            SessionInner::None => Ok(None),
        }
    }

    /// Set a `value` from the session.
    pub fn set<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
        match self.0 {
            SessionInner::Session(ref sess) => {
                sess.as_ref()
                    .0
                    .borrow_mut()
                    .set(key, serde_json::to_string(&value)?);
                Ok(())
            }
            SessionInner::None => Ok(()),
        }
    }

    /// Remove value from the session.
    pub fn remove(&self, key: &str) {
        match self.0 {
            SessionInner::Session(ref sess) => sess.as_ref().0.borrow_mut().remove(key),
            SessionInner::None => (),
        }
    }

    /// Clear the session.
    pub fn clear(&self) {
        match self.0 {
            SessionInner::Session(ref sess) => sess.as_ref().0.borrow_mut().clear(),
            SessionInner::None => (),
        }
    }
}

/// Extractor implementation for Session type.
///
/// ```rust
/// # use actix_web::*;
/// use actix_web::middleware::session::Session;
///
/// fn index(session: Session) -> Result<&'static str> {
///     // access session data
///     if let Some(count) = session.get::<i32>("counter")? {
///         session.set("counter", count + 1)?;
///     } else {
///         session.set("counter", 1)?;
///     }
///
///     Ok("Welcome!")
/// }
/// # fn main() {}
/// ```
impl<S> FromRequest<S> for Session {
    type Config = ();
    type Result = Session;

    #[inline]
    fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
        req.session()
    }
}

struct SessionImplCell(RefCell<Box<SessionImpl>>);

/// Session storage middleware
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::middleware::session::{CookieSessionBackend, SessionStorage};
/// use actix_web::App;
///
/// fn main() {
///     let app = App::new().middleware(SessionStorage::new(
///         // <- create session middleware
///         CookieSessionBackend::signed(&[0; 32]) // <- create cookie session backend
///               .secure(false),
///     ));
/// }
/// ```
pub struct SessionStorage<T, S>(T, PhantomData<S>);

impl<S, T: SessionBackend<S>> SessionStorage<T, S> {
    /// Create session storage
    pub fn new(backend: T) -> SessionStorage<T, S> {
        SessionStorage(backend, PhantomData)
    }
}

impl<S: 'static, T: SessionBackend<S>> Middleware<S> for SessionStorage<T, S> {
    fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
        let mut req = req.clone();

        let fut = self.0.from_request(&mut req).then(move |res| match res {
            Ok(sess) => {
                req.extensions_mut()
                    .insert(Arc::new(SessionImplCell(RefCell::new(Box::new(sess)))));
                FutOk(None)
            }
            Err(err) => FutErr(err),
        });
        Ok(Started::Future(Box::new(fut)))
    }

    fn response(&self, req: &HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
        if let Some(s_box) = req.extensions().get::<Arc<SessionImplCell>>() {
            s_box.0.borrow_mut().write(resp)
        } else {
            Ok(Response::Done(resp))
        }
    }
}

/// A simple key-value storage interface that is internally used by `Session`.
pub trait SessionImpl: 'static {
    /// Get session value by key
    fn get(&self, key: &str) -> Option<&str>;

    /// Set session value
    fn set(&mut self, key: &str, value: String);

    /// Remove specific key from session
    fn remove(&mut self, key: &str);

    /// Remove all values from session
    fn clear(&mut self);

    /// Write session to storage backend.
    fn write(&self, resp: HttpResponse) -> Result<Response>;
}

/// Session's storage backend trait definition.
pub trait SessionBackend<S>: Sized + 'static {
    /// Session item
    type Session: SessionImpl;
    /// Future that reads session
    type ReadFuture: Future<Item = Self::Session, Error = Error>;

    /// Parse the session from request and load data from a storage backend.
    fn from_request(&self, request: &mut HttpRequest<S>) -> Self::ReadFuture;
}

/// Session that uses signed cookies as session storage
pub struct CookieSession {
    changed: bool,
    state: HashMap<String, String>,
    inner: Rc<CookieSessionInner>,
}

/// Errors that can occur during handling cookie session
#[derive(Fail, Debug)]
pub enum CookieSessionError {
    /// Size of the serialized session is greater than 4000 bytes.
    #[fail(display = "Size of the serialized session is greater than 4000 bytes.")]
    Overflow,
    /// Fail to serialize session.
    #[fail(display = "Fail to serialize session")]
    Serialize(JsonError),
}

impl ResponseError for CookieSessionError {}

impl SessionImpl for CookieSession {
    fn get(&self, key: &str) -> Option<&str> {
        if let Some(s) = self.state.get(key) {
            Some(s)
        } else {
            None
        }
    }

    fn set(&mut self, key: &str, value: String) {
        self.changed = true;
        self.state.insert(key.to_owned(), value);
    }

    fn remove(&mut self, key: &str) {
        self.changed = true;
        self.state.remove(key);
    }

    fn clear(&mut self) {
        self.changed = true;
        self.state.clear()
    }

    fn write(&self, mut resp: HttpResponse) -> Result<Response> {
        if self.changed {
            let _ = self.inner.set_cookie(&mut resp, &self.state);
        }
        Ok(Response::Done(resp))
    }
}

enum CookieSecurity {
    Signed,
    Private,
}

struct CookieSessionInner {
    key: Key,
    security: CookieSecurity,
    name: String,
    path: String,
    domain: Option<String>,
    secure: bool,
    http_only: bool,
    max_age: Option<Duration>,
    same_site: Option<SameSite>,
}

impl CookieSessionInner {
    fn new(key: &[u8], security: CookieSecurity) -> CookieSessionInner {
        CookieSessionInner {
            security,
            key: Key::from_master(key),
            name: "actix-session".to_owned(),
            path: "/".to_owned(),
            domain: None,
            secure: true,
            http_only: true,
            max_age: None,
            same_site: None,
        }
    }

    fn set_cookie(
        &self, resp: &mut HttpResponse, state: &HashMap<String, String>,
    ) -> Result<()> {
        let value =
            serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
        if value.len() > 4064 {
            return Err(CookieSessionError::Overflow.into());
        }

        let mut cookie = Cookie::new(self.name.clone(), value);
        cookie.set_path(self.path.clone());
        cookie.set_secure(self.secure);
        cookie.set_http_only(self.http_only);

        if let Some(ref domain) = self.domain {
            cookie.set_domain(domain.clone());
        }

        if let Some(max_age) = self.max_age {
            cookie.set_max_age(max_age);
        }

        if let Some(same_site) = self.same_site {
            cookie.set_same_site(same_site);
        }

        let mut jar = CookieJar::new();

        match self.security {
            CookieSecurity::Signed => jar.signed(&self.key).add(cookie),
            CookieSecurity::Private => jar.private(&self.key).add(cookie),
        }

        for cookie in jar.delta() {
            let val = HeaderValue::from_str(&cookie.encoded().to_string())?;
            resp.headers_mut().append(header::SET_COOKIE, val);
        }

        Ok(())
    }

    fn load<S>(&self, req: &mut HttpRequest<S>) -> HashMap<String, String> {
        if let Ok(cookies) = req.cookies() {
            for cookie in cookies.iter() {
                if cookie.name() == self.name {
                    let mut jar = CookieJar::new();
                    jar.add_original(cookie.clone());

                    let cookie_opt = match self.security {
                        CookieSecurity::Signed => jar.signed(&self.key).get(&self.name),
                        CookieSecurity::Private => {
                            jar.private(&self.key).get(&self.name)
                        }
                    };
                    if let Some(cookie) = cookie_opt {
                        if let Ok(val) = serde_json::from_str(cookie.value()) {
                            return val;
                        }
                    }
                }
            }
        }
        HashMap::new()
    }
}

/// Use cookies for session storage.
///
/// `CookieSessionBackend` creates sessions which are limited to storing
/// fewer than 4000 bytes of data (as the payload must fit into a single
/// cookie). An Internal Server Error is generated if the session contains more
/// than 4000 bytes.
///
/// A cookie may have a security policy of *signed* or *private*. Each has a
/// respective `CookieSessionBackend` constructor.
///
/// A *signed* cookie is stored on the client as plaintext alongside
/// a signature such that the cookie may be viewed but not modified by the
/// client.
///
/// A *private* cookie is stored on the client as encrypted text
/// such that it may neither be viewed nor modified by the client.
///
/// The constructors take a key as an argument.
/// This is the private key for cookie session - when this value is changed,
/// all session data is lost. The constructors will panic if the key is less
/// than 32 bytes in length.
///
/// The backend relies on `cookie` crate to create and read cookies.
/// By default all cookies are percent encoded, but certain symbols may
/// cause troubles when reading cookie, if they are not properly percent encoded.
///
/// # Example
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::middleware::session::CookieSessionBackend;
///
/// # fn main() {
/// let backend: CookieSessionBackend = CookieSessionBackend::signed(&[0; 32])
///     .domain("www.rust-lang.org")
///     .name("actix_session")
///     .path("/")
///     .secure(true);
/// # }
/// ```
pub struct CookieSessionBackend(Rc<CookieSessionInner>);

impl CookieSessionBackend {
    /// Construct new *signed* `CookieSessionBackend` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn signed(key: &[u8]) -> CookieSessionBackend {
        CookieSessionBackend(Rc::new(CookieSessionInner::new(
            key,
            CookieSecurity::Signed,
        )))
    }

    /// Construct new *private* `CookieSessionBackend` instance.
    ///
    /// Panics if key length is less than 32 bytes.
    pub fn private(key: &[u8]) -> CookieSessionBackend {
        CookieSessionBackend(Rc::new(CookieSessionInner::new(
            key,
            CookieSecurity::Private,
        )))
    }

    /// Sets the `path` field in the session cookie being built.
    pub fn path<S: Into<String>>(mut self, value: S) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().path = value.into();
        self
    }

    /// Sets the `name` field in the session cookie being built.
    pub fn name<S: Into<String>>(mut self, value: S) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().name = value.into();
        self
    }

    /// Sets the `domain` field in the session cookie being built.
    pub fn domain<S: Into<String>>(mut self, value: S) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().domain = Some(value.into());
        self
    }

    /// Sets the `secure` field in the session cookie being built.
    ///
    /// If the `secure` field is set, a cookie will only be transmitted when the
    /// connection is secure - i.e. `https`
    pub fn secure(mut self, value: bool) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().secure = value;
        self
    }

    /// Sets the `http_only` field in the session cookie being built.
    pub fn http_only(mut self, value: bool) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().http_only = value;
        self
    }

    /// Sets the `same_site` field in the session cookie being built.
    pub fn same_site(mut self, value: SameSite) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().same_site = Some(value);
        self
    }

    /// Sets the `max-age` field in the session cookie being built.
    pub fn max_age(mut self, value: Duration) -> CookieSessionBackend {
        Rc::get_mut(&mut self.0).unwrap().max_age = Some(value);
        self
    }
}

impl<S> SessionBackend<S> for CookieSessionBackend {
    type Session = CookieSession;
    type ReadFuture = FutureResult<CookieSession, Error>;

    fn from_request(&self, req: &mut HttpRequest<S>) -> Self::ReadFuture {
        let state = self.0.load(req);
        FutOk(CookieSession {
            changed: false,
            inner: Rc::clone(&self.0),
            state,
        })
    }
}

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

    #[test]
    fn cookie_session() {
        let mut srv = test::TestServer::with_factory(|| {
            App::new()
                .middleware(SessionStorage::new(
                    CookieSessionBackend::signed(&[0; 32]).secure(false),
                )).resource("/", |r| {
                    r.f(|req| {
                        let _ = req.session().set("counter", 100);
                        "test"
                    })
                })
        });

        let request = srv.get().uri(srv.url("/")).finish().unwrap();
        let response = srv.execute(request.send()).unwrap();
        assert!(response.cookie("actix-session").is_some());
    }

    #[test]
    fn cookie_session_extractor() {
        let mut srv = test::TestServer::with_factory(|| {
            App::new()
                .middleware(SessionStorage::new(
                    CookieSessionBackend::signed(&[0; 32]).secure(false),
                )).resource("/", |r| {
                    r.with(|ses: Session| {
                        let _ = ses.set("counter", 100);
                        "test"
                    })
                })
        });

        let request = srv.get().uri(srv.url("/")).finish().unwrap();
        let response = srv.execute(request.send()).unwrap();
        assert!(response.cookie("actix-session").is_some());
    }
}
<|endoftext|>


<commit_before>import option::some;
import option::none;

// FIXME: It would probably be more appealing to define this as
// type list[T] = rec(T hd, option[@list[T]] tl), but at the moment
// our recursion rules do not permit that.

tag list[T] {
    cons(T, @list[T]);
    nil;
}

fn from_vec[T](vec[T] v) -> list[T] {
    auto l = nil[T];
    // FIXME: This would be faster and more space efficient if it looped over
    // a reverse vector iterator. Unfortunately generic iterators seem not to
    // work yet.
    for (T item in vec::reversed(v)) {
        l = cons[T](item, @l);
    }
    ret l;
}

fn foldl[T,U](&list[T] ls, &U u, fn(&T t, &U u) -> U f) -> U {
    alt(ls) {
        case (cons[T](?hd, ?tl)) {
            auto u_ = f(hd, u);
            be foldl[T,U](*tl, u_, f);
        }
        case (nil[T]) {
            ret u;
        }
    }
}

fn find[T,U](&list[T] ls,
             (fn(&T) -> option::t[U]) f) -> option::t[U] {
    alt(ls) {
        case (cons[T](?hd, ?tl)) {
            alt (f(hd)) {
                case (none[U]) {
                    be find[T,U](*tl, f);
                }
                case (some[U](?res)) {
                    ret some[U](res);
                }
            }
        }
        case (nil[T]) {
            ret none[U];
        }
    }
}

fn length[T](&list[T] ls) -> uint {
    fn count[T](&T t, &uint u) -> uint {
        ret u + 1u;
    }
    ret foldl[T,uint](ls, 0u, bind count[T](_, _));
}

fn cdr[T](&list[T] ls) -> list[T] {
    alt (ls) {
        case (cons[T](_, ?tl)) {ret *tl;}
    }
}
fn car[T](&list[T] ls) -> T {
    alt (ls) {
        case (cons[T](?hd, _)) {ret hd;}
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add a list append function, which I didn't end up using, but why not add it?<commit_after>import option::some;
import option::none;

// FIXME: It would probably be more appealing to define this as
// type list[T] = rec(T hd, option[@list[T]] tl), but at the moment
// our recursion rules do not permit that.

tag list[T] {
    cons(T, @list[T]);
    nil;
}

fn from_vec[T](vec[T] v) -> list[T] {
    auto l = nil[T];
    // FIXME: This would be faster and more space efficient if it looped over
    // a reverse vector iterator. Unfortunately generic iterators seem not to
    // work yet.
    for (T item in vec::reversed(v)) {
        l = cons[T](item, @l);
    }
    ret l;
}

fn foldl[T,U](&list[T] ls, &U u, fn(&T t, &U u) -> U f) -> U {
    alt(ls) {
        case (cons[T](?hd, ?tl)) {
            auto u_ = f(hd, u);
            be foldl[T,U](*tl, u_, f);
        }
        case (nil[T]) {
            ret u;
        }
    }
}

fn find[T,U](&list[T] ls,
             (fn(&T) -> option::t[U]) f) -> option::t[U] {
    alt(ls) {
        case (cons[T](?hd, ?tl)) {
            alt (f(hd)) {
                case (none[U]) {
                    be find[T,U](*tl, f);
                }
                case (some[U](?res)) {
                    ret some[U](res);
                }
            }
        }
        case (nil[T]) {
            ret none[U];
        }
    }
}

fn length[T](&list[T] ls) -> uint {
    fn count[T](&T t, &uint u) -> uint {
        ret u + 1u;
    }
    ret foldl[T,uint](ls, 0u, bind count[T](_, _));
}

fn cdr[T](&list[T] ls) -> list[T] {
    alt (ls) {
        case (cons[T](_, ?tl)) {ret *tl;}
    }
}
fn car[T](&list[T] ls) -> T {
    alt (ls) {
        case (cons[T](?hd, _)) {ret hd;}
    }
}

fn append[T](&list[T] l, &list[T] m) -> list[T] {
    alt (l) {
        case (nil[T]) {
            ret m;
        }
        case (cons[T](?x, ?xs)) {
            let list[T] rest = append[T](*xs, m);
            ret cons[T](x, @rest);
        }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before><commit_msg>Enable cursor and pointer-events in 2020<commit_after><|endoftext|>


<commit_before>// 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/.

use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::slice::Iter;
use std::string::String;
use std::sync::Arc;

use dbus;
use dbus::Connection;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;

use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MethodFn;
use dbus::tree::MethodResult;
use dbus::tree::Property;
use dbus::tree::Tree;

use dbus_consts::*;

use engine::Engine;

use types::{StratisResult, StratisError};

#[derive(Debug, Clone)]
pub struct DbusContext<'a> {
    name_prop: Arc<Property<MethodFn<'a>>>,
    pub remaining_prop: Arc<Property<MethodFn<'a>>>,
    pub total_prop: Arc<Property<MethodFn<'a>>>,
    pub status_prop: Arc<Property<MethodFn<'a>>>,
    pub running_status_prop: Arc<Property<MethodFn<'a>>>,
    pub block_devices_prop: Arc<Property<MethodFn<'a>>>,
}

impl<'a> DbusContext<'a> {
    pub fn update_one(prop: &Arc<Property<MethodFn<'a>>>, m: MessageItem) -> StratisResult<()> {
        match prop.set_value(m) {
            Ok(_) => Ok(()), // TODO: return signals
            Err(()) => Err(StratisError::Dbus(dbus::Error::new_custom(
                "UpdateError", "Could not update property with value"))),
        }
    }
}

fn listpools(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    Ok(vec![m.method_return()])
}

fn createpool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let raid_level: u16 = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner()
                .map_err(|_| MethodErr::invalid_arg(&i))
        }));

    let devs = match try!(items.pop().ok_or_else(MethodErr::no_arg)) {
        MessageItem::Array(x, _) => x,
        x => return Err(MethodErr::invalid_arg(&x)),
    };

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    // TODO: figure out how to convert devs to &[], or should
    // we be using PathBuf like Foryo does?
    let result = engine.borrow().create_pool(&name, &[], raid_level);

    Ok(vec![m.method_return().append3("/dbus/newpool/path", 0, "Ok")])
}

fn destroypool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let result = engine.borrow().destroy_pool(&name);

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn getpoolobjectpath(m: &Message) -> MethodResult {

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn getvolumeobjectpath(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/volume/path", 0, "Ok")])
}

fn getdevobjectpath(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/dev/path", 0, "Ok")])
}

fn getcacheobjectpath(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/cache/path", 0, "Ok")])
}

fn getlistitems<T: HasCodes + Display>(m: &Message, items: &Iter<T>) -> MethodResult {

    let mut msg_vec = Vec::new();
    for item in items.as_slice() {
        let entry = vec![MessageItem::Str(format!("{}", item)),
                         MessageItem::UInt16(item.get_error_int()),
                         MessageItem::Str(String::from(item.get_error_string()))];
        msg_vec.push(MessageItem::Struct(entry));
    }

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));
    Ok(vec![m.method_return().append1(item_array)])
}

fn geterrorcodes(m: &Message) -> MethodResult {
    getlistitems(m, &StratisErrorEnum::iterator())
}

fn getraidlevels(m: &Message) -> MethodResult {
    getlistitems(m, &StratisRaidType::iterator())
}

fn getdevtypes(m: &Message) -> MethodResult {
    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let _name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    println!("method called");

    Ok(vec![m.method_return()])
}

pub fn get_base_tree<'a>(c: &'a Connection,
                         engine: Rc<RefCell<Engine>>)
                         -> StratisResult<Tree<MethodFn<'a>>> {
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32).unwrap();

    let f = Factory::new_fn();

    let base_tree = f.tree();

    let engine_clone = engine.clone();

    let createpool_method = f.method(CREATE_POOL, move |m, _, _| createpool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .in_arg(("dev_list", "as"))
        .in_arg(("raid_type", "q"))
        .out_arg(("object_path", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let destroypool_method = f.method(DESTROY_POOL, move |m, _, _| destroypool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let listpools_method = f.method(LIST_POOLS, move |m, _, _| listpools(m, &engine_clone))
        .out_arg(("pool_names", "as"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getpoolobjectpath_method =
        f.method(GET_POOL_OBJECT_PATH, move |m, _, _| getpoolobjectpath(m))
            .in_arg(("pool_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getvolumeobjectpath_method = f.method(GET_VOLUME_OBJECT_PATH,
                move |m, _, _| getvolumeobjectpath(m))
        .in_arg(("pool_name", "s"))
        .in_arg(("volume_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getdevobjectpath_method = f.method(GET_DEV_OBJECT_PATH, move |m, _, _| getdevobjectpath(m))
        .in_arg(("dev_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getcacheobjectpath_method =
        f.method(GET_CACHE_OBJECT_PATH, move |m, _, _| getcacheobjectpath(m))
            .in_arg(("cache_dev_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let geterrorcodes_method = f.method(GET_ERROR_CODES, move |m, _, _| geterrorcodes(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getraidlevels_method = f.method(GET_RAID_LEVELS, move |m, _, _| getraidlevels(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getdevtypes_method = f.method(GET_DEV_TYPES, move |m, _, _| getdevtypes(m));

    let obj_path = f.object_path(STRATIS_BASE_PATH)
        .introspectable()
        .add(f.interface(STRATIS_MANAGER_INTERFACE)
            .add_m(listpools_method)
            .add_m(createpool_method)
            .add_m(destroypool_method)
            .add_m(getpoolobjectpath_method)
            .add_m(getvolumeobjectpath_method)
            .add_m(getdevobjectpath_method)
            .add_m(getcacheobjectpath_method)
            .add_m(geterrorcodes_method)
            .add_m(getraidlevels_method)
            .add_m(getdevtypes_method));

    let base_tree = base_tree.add(obj_path);
    try!(base_tree.set_registered(c, true));

    Ok(base_tree)
}
<commit_msg>remove un-used import<commit_after>// 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/.

use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Display;
use std::rc::Rc;
use std::slice::Iter;
use std::string::String;
use std::sync::Arc;

use dbus;
use dbus::Connection;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;

use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MethodFn;
use dbus::tree::MethodResult;
use dbus::tree::Property;
use dbus::tree::Tree;

use dbus_consts::*;

use engine::Engine;

use types::{StratisResult, StratisError};

#[derive(Debug, Clone)]
pub struct DbusContext<'a> {
    name_prop: Arc<Property<MethodFn<'a>>>,
    pub remaining_prop: Arc<Property<MethodFn<'a>>>,
    pub total_prop: Arc<Property<MethodFn<'a>>>,
    pub status_prop: Arc<Property<MethodFn<'a>>>,
    pub running_status_prop: Arc<Property<MethodFn<'a>>>,
    pub block_devices_prop: Arc<Property<MethodFn<'a>>>,
}

impl<'a> DbusContext<'a> {
    pub fn update_one(prop: &Arc<Property<MethodFn<'a>>>, m: MessageItem) -> StratisResult<()> {
        match prop.set_value(m) {
            Ok(_) => Ok(()), // TODO: return signals
            Err(()) => Err(StratisError::Dbus(dbus::Error::new_custom(
                "UpdateError", "Could not update property with value"))),
        }
    }
}

fn listpools(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    Ok(vec![m.method_return()])
}

fn createpool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let raid_level: u16 = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner()
                .map_err(|_| MethodErr::invalid_arg(&i))
        }));

    let devs = match try!(items.pop().ok_or_else(MethodErr::no_arg)) {
        MessageItem::Array(x, _) => x,
        x => return Err(MethodErr::invalid_arg(&x)),
    };

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    // TODO: figure out how to convert devs to &[], or should
    // we be using PathBuf like Foryo does?
    let result = engine.borrow().create_pool(&name, &[], raid_level);

    Ok(vec![m.method_return().append3("/dbus/newpool/path", 0, "Ok")])
}

fn destroypool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let result = engine.borrow().destroy_pool(&name);

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn getpoolobjectpath(m: &Message) -> MethodResult {

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn getvolumeobjectpath(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/volume/path", 0, "Ok")])
}

fn getdevobjectpath(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/dev/path", 0, "Ok")])
}

fn getcacheobjectpath(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/cache/path", 0, "Ok")])
}

fn getlistitems<T: HasCodes + Display>(m: &Message, items: &Iter<T>) -> MethodResult {

    let mut msg_vec = Vec::new();
    for item in items.as_slice() {
        let entry = vec![MessageItem::Str(format!("{}", item)),
                         MessageItem::UInt16(item.get_error_int()),
                         MessageItem::Str(String::from(item.get_error_string()))];
        msg_vec.push(MessageItem::Struct(entry));
    }

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));
    Ok(vec![m.method_return().append1(item_array)])
}

fn geterrorcodes(m: &Message) -> MethodResult {
    getlistitems(m, &StratisErrorEnum::iterator())
}

fn getraidlevels(m: &Message) -> MethodResult {
    getlistitems(m, &StratisRaidType::iterator())
}

fn getdevtypes(m: &Message) -> MethodResult {
    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let _name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    println!("method called");

    Ok(vec![m.method_return()])
}

pub fn get_base_tree<'a>(c: &'a Connection,
                         engine: Rc<RefCell<Engine>>)
                         -> StratisResult<Tree<MethodFn<'a>>> {
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32).unwrap();

    let f = Factory::new_fn();

    let base_tree = f.tree();

    let engine_clone = engine.clone();

    let createpool_method = f.method(CREATE_POOL, move |m, _, _| createpool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .in_arg(("dev_list", "as"))
        .in_arg(("raid_type", "q"))
        .out_arg(("object_path", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let destroypool_method = f.method(DESTROY_POOL, move |m, _, _| destroypool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let listpools_method = f.method(LIST_POOLS, move |m, _, _| listpools(m, &engine_clone))
        .out_arg(("pool_names", "as"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getpoolobjectpath_method =
        f.method(GET_POOL_OBJECT_PATH, move |m, _, _| getpoolobjectpath(m))
            .in_arg(("pool_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getvolumeobjectpath_method = f.method(GET_VOLUME_OBJECT_PATH,
                move |m, _, _| getvolumeobjectpath(m))
        .in_arg(("pool_name", "s"))
        .in_arg(("volume_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getdevobjectpath_method = f.method(GET_DEV_OBJECT_PATH, move |m, _, _| getdevobjectpath(m))
        .in_arg(("dev_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getcacheobjectpath_method =
        f.method(GET_CACHE_OBJECT_PATH, move |m, _, _| getcacheobjectpath(m))
            .in_arg(("cache_dev_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let geterrorcodes_method = f.method(GET_ERROR_CODES, move |m, _, _| geterrorcodes(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getraidlevels_method = f.method(GET_RAID_LEVELS, move |m, _, _| getraidlevels(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getdevtypes_method = f.method(GET_DEV_TYPES, move |m, _, _| getdevtypes(m));

    let obj_path = f.object_path(STRATIS_BASE_PATH)
        .introspectable()
        .add(f.interface(STRATIS_MANAGER_INTERFACE)
            .add_m(listpools_method)
            .add_m(createpool_method)
            .add_m(destroypool_method)
            .add_m(getpoolobjectpath_method)
            .add_m(getvolumeobjectpath_method)
            .add_m(getdevobjectpath_method)
            .add_m(getcacheobjectpath_method)
            .add_m(geterrorcodes_method)
            .add_m(getraidlevels_method)
            .add_m(getdevtypes_method));

    let base_tree = base_tree.add(obj_path);
    try!(base_tree.set_registered(c, true));

    Ok(base_tree)
}
<|endoftext|>


<commit_before><commit_msg>Rollup merge of #26388 - frewsxcv:regression-tests-21622, r=alexcrichton<commit_after>// Copyright 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.

struct Index;

impl Index {
    fn new() -> Self { Index }
}

fn user() {
    let new = Index::new;

    fn inner() {
        let index = Index::new();
    }

    let index2 = new();
}

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Auto merge of #24979 - jooert:test-22471, r=pnkfelix<commit_after>// Copyright 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.

type Foo<T> where T: Copy = Box<T>;

fn main(){}
<|endoftext|>


<commit_before><commit_msg>Rollup merge of #26387 - frewsxcv:regression-tests-25180, r=eddyb<commit_after>// Copyright 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.

const x: &'static Fn() = &|| println!("ICE here");

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Add regression test.<commit_after>// Copyright 2016 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.

macro_rules! m { (<$t:ty>) => { stringify!($t) } }
fn main() {
    println!("{}", m!(<Vec<i32>>));
}
<|endoftext|>


<commit_before>
use spirv_utils::{self, desc, instruction};
use core;
use core::shade::{self, BaseType, ContainerType, TextureType};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Variable {
    id: desc::Id,
    name: String,
    ty: desc::Id,
    storage_class: desc::StorageClass,
    decoration: Vec<instruction::Decoration>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct EntryPoint {
    name: String,
    stage: shade::Stage,
    interface: Box<[desc::Id]>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Ty {
    Basic(BaseType, ContainerType),
    Image(BaseType, TextureType),
    Struct(Vec<Type>),
    Sampler,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Type {
    id: desc::Id,
    ty: Ty,
    decoration: Vec<instruction::Decoration>,
}

fn map_execution_model_to_stage(model: desc::ExecutionModel) -> Option<shade::Stage> {
    use spirv_utils::desc::ExecutionModel::*;
    match model {
        Vertex => Some(shade::Stage::Vertex),
        Geometry => Some(shade::Stage::Geometry),
        Fragment => Some(shade::Stage::Pixel),

        _ => None,
    }
}

fn map_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Name { ref name, .. } => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_member_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberName { ref name, member, .. } if member == member_id => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Decorate { ref decoration, .. } => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_member_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberDecorate { ref decoration, member, .. } if member == member_id => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_image_to_texture_type(dim: desc::Dim, arrayed: bool, multisampled: bool) -> TextureType {
    use spirv_utils::desc::Dim;
    let arrayed = if arrayed { shade::IsArray::Array } else { shade::IsArray::NoArray };
    let multisampled = if multisampled { shade::IsMultiSample::MultiSample } else { shade::IsMultiSample::NoMultiSample };
    match dim {
        Dim::_1D => shade::TextureType::D1(arrayed),
        Dim::_2D => shade::TextureType::D2(arrayed, multisampled),
        Dim::_3D => shade::TextureType::D3,
        Dim::Cube => shade::TextureType::Cube(arrayed),
        Dim::Buffer => shade::TextureType::Buffer,

        _ => unimplemented!(),
    }
}

fn map_scalar_to_basetype(instr: &instruction::Instruction) -> Option<BaseType> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { .. } => Some(BaseType::Bool),
        Instruction::TypeInt { width: 32, signed: false, .. } => Some(BaseType::U32),
        Instruction::TypeInt { width: 32, signed: true, .. } => Some(BaseType::I32),
        Instruction::TypeFloat { width: 32, ..} => Some(BaseType::F32),
        Instruction::TypeFloat { width: 64, ..} => Some(BaseType::F64),

        _ => None,
    }
}

fn map_instruction_to_type(module: &spirv_utils::RawModule, instr: &instruction::Instruction) -> Option<Type> {
    use spirv_utils::instruction::{Decoration, Instruction};
    let id_ty = match *instr {
        Instruction::TypeBool { result_type } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: false } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: true } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 32 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 64 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeVector { result_type, type_id, len } => {
            let comp_ty = module.def(type_id).unwrap();
            Some((result_type, Ty::Basic(map_scalar_to_basetype(comp_ty).unwrap(), ContainerType::Vector(len as u8))))
        },
        Instruction::TypeMatrix { result_type, type_id, cols } => {
            let (base, rows) = match *module.def(type_id).unwrap() {
                Instruction::TypeVector { type_id, len, .. } => {
                    let comp_ty = module.def(type_id).unwrap();
                    (map_scalar_to_basetype(comp_ty).unwrap(), len)
                },
                _ => unreachable!(), // SPIR-V module would be invalid
            };

            let decoration = map_decorations_by_id(&module, result_type.into());

            // NOTE: temporary value, changes might be needed later depending on the decorations of the variable
            let matrix_format = if decoration.iter().find(|deco| **deco == Decoration::RowMajor).is_some() {
                shade::MatrixFormat::RowMajor
            } else {
                shade::MatrixFormat::ColumnMajor
            };

            Some((result_type, Ty::Basic(base, ContainerType::Matrix(matrix_format, rows as u8, cols as u8))))
        },
        Instruction::TypeStruct { result_type, ref fields } => {
            Some((
                result_type,
                Ty::Struct(
                    fields.iter().filter_map(|field| // TODO: should be `map()`, currently to ignore unsupported types
                        map_instruction_to_type(module, module.def(*field).unwrap())
                    ).collect::<Vec<_>>()
                )
            ))
        },
        Instruction::TypeSampler { result_type } => {
            Some((result_type, Ty::Sampler))
        },
        Instruction::TypeImage { result_type, type_id, dim, arrayed, multisampled, .. } => {
            Some((result_type, Ty::Image(map_scalar_to_basetype(module.def(type_id).unwrap()).unwrap(), map_image_to_texture_type(dim, arrayed, multisampled))))
        },

        _ => None,
    };

    id_ty.map(|(id, ty)| Type {
            id: id.into(),
            ty: ty,
            decoration: map_decorations_by_id(&module, id.into()),
        })
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SpirvReflection {
    entry_points: Vec<EntryPoint>,
    variables: Vec<Variable>,
    types: Vec<Type>,
}

pub fn reflect_spirv_module(code: &[u8]) -> SpirvReflection {
    use spirv_utils::instruction::Instruction;

    let module = spirv_utils::RawModule::read_module(code).unwrap();

    let mut entry_points = Vec::new();
    let mut variables = Vec::new();
    let mut types = Vec::new();
    for instr in module.instructions() {
        match *instr {
            Instruction::EntryPoint { execution_model, ref name, ref interface, .. } => {
                if let Some(stage) = map_execution_model_to_stage(execution_model) {
                    entry_points.push(EntryPoint {
                        name: name.clone(),
                        stage: stage,
                        interface: interface.clone(),
                    });
                } else {
                    error!("Unsupported execution model: {:?}", execution_model);
                }
            },
            Instruction::Variable { result_type, result_id, storage_class, .. } => {
                let decoration = map_decorations_by_id(&module, result_id.into());
                let ty = {
                    // remove indirection layer as the type of every variable is a OpTypePointer
                    let ptr_ty = module.def::<desc::TypeId>(result_type.into()).unwrap();
                    match *ptr_ty {
                        Instruction::TypePointer { ref pointee, .. } => *pointee,
                        _ => unreachable!(), // SPIR-V module would be invalid
                    }
                };

                // Every variable MUST have an name annotation
                // `glslang` seems to emit empty strings for uniforms with struct type,
                // therefore we need to retrieve the name from the struct decl
                let name = {
                    let name = map_name_by_id(&module, result_id.into()).unwrap();
                    if name.is_empty() {
                        map_name_by_id(&module, ty.into()).unwrap()
                    } else {
                        name
                    }
                };

                variables.push(Variable {
                    id: result_id.into(),
                    name: name.into(),
                    ty: ty.into(),
                    storage_class: storage_class,
                    decoration: decoration,
                });
            },

            _ => {
                // Reflect types, if we have OpTypeXXX
                if let Some(ty) = map_instruction_to_type(&module, instr) {
                    types.push(ty);
                }
            },
        }
    }

    SpirvReflection {
        entry_points: entry_points,
        variables: variables,
        types: types,
    }
}

pub fn populate_info(info: &mut shade::ProgramInfo, stage: shade::Stage, reflection: &SpirvReflection) {
    if stage == shade::Stage::Vertex {
        // record vertex attributes
        let entry_point = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage).expect("Couln't find entry point!");
        for attrib in entry_point.interface.iter() {
            if let Some(var) = reflection.variables.iter().find(|var| var.id == *attrib) {
                if var.storage_class == desc::StorageClass::Input {
                    let attrib_name = var.name.clone();
                    let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                    instruction::Decoration::Location(slot) => Some(slot),
                                    _ => None,
                                }).next().expect("Missing location decoration");

                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.vertex_attributes.push(shade::AttributeVar {
                            name: attrib_name,
                            slot: slot as core::AttributeSlot,
                            base_type: base,
                            container: container,
                        });
                    } else {
                        error!("Unsupported type as vertex attribute: {:?}", ty.ty);
                    }
                }
            } else {
                error!("Missing vertex attribute reflection: {:?}", attrib);
            }
        }
    } else if stage == shade::Stage::Pixel {
        // record pixel outputs
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for out in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *out) {
                    if var.storage_class == desc::StorageClass::Output {
                        let target_name = var.name.clone();
                        let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                        instruction::Decoration::Location(slot) => Some(slot),
                                        _ => None,
                                    }).next().expect("Missing location decoration");

                        let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                        if let Ty::Basic(base, container) = ty.ty {
                            info.outputs.push(shade::OutputVar {
                                name: target_name,
                                slot: slot as core::ColorSlot,
                                base_type: base,
                                container: container,
                            });
                        } else {
                            error!("Unsupported type as pixel shader output: {:?}", ty.ty);
                        }
                    }
                } else {
                    error!("Missing pixel shader output reflection: {:?}", out);
                }
            }
        }
    }

    // Handle resources
    // We use only one descriptor set currently
    for var in reflection.variables.iter() {
        use spirv_utils::desc::StorageClass::*;
        match var.storage_class {
            Uniform | UniformConstant => {
                if let Some(ty) = reflection.types.iter().find(|ty| ty.id == var.ty) {
                    // constant buffers
                    match ty.ty {
                        Ty::Struct(ref fields) => {
                            let mut elements = Vec::new();
                            for field in fields {
                                // TODO:
                            }

                            let buffer_name = var.name.clone();
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.constant_buffers.push(shade::ConstantBufferVar {
                                name: buffer_name,
                                slot: slot as core::ConstantBufferSlot,
                                size: 0, // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                                elements: elements,
                            });
                        },

                        Ty::Sampler => {
                            let sampler_name = var.name.trim_right_matches('_');
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.samplers.push(shade::SamplerVar {
                                name: sampler_name.to_owned(),
                                slot: slot as core::SamplerSlot,
                                ty: shade::SamplerType(shade::IsComparison::NoCompare, shade::IsRect::NoRect), // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        Ty::Image(base_type, texture_type) => {
                            let texture_name = var.name.clone();
                            let slot = var.decoration.iter().filter_map(|dec| match *dec {
                                            instruction::Decoration::Binding(slot) => Some(slot),
                                            _ => None,
                                        }).next().expect("Missing binding decoration");

                            info.textures.push(shade::TextureVar {
                                name: texture_name,
                                slot: slot as core::ResourceViewSlot,
                                base_type: base_type,
                                ty: texture_type,
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        _ => (),
                    }
                } else {
                    error!("Unsupported uniform type: {:?}", var.ty);
                }
            },
            _ => (),
        }
    }
}
<commit_msg>Vulkan: Further code cleanup and error handling<commit_after>
use spirv_utils::{self, desc, instruction};
use core;
use core::shade::{self, BaseType, ContainerType, TextureType};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Variable {
    id: desc::Id,
    name: String,
    ty: desc::Id,
    storage_class: desc::StorageClass,
    decoration: Vec<instruction::Decoration>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct EntryPoint {
    name: String,
    stage: shade::Stage,
    interface: Box<[desc::Id]>,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Ty {
    Basic(BaseType, ContainerType),
    Image(BaseType, TextureType),
    Struct(Vec<Type>),
    Sampler,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Type {
    id: desc::Id,
    ty: Ty,
    decoration: Vec<instruction::Decoration>,
}

fn map_execution_model_to_stage(model: desc::ExecutionModel) -> Option<shade::Stage> {
    use spirv_utils::desc::ExecutionModel::*;
    match model {
        Vertex => Some(shade::Stage::Vertex),
        Geometry => Some(shade::Stage::Geometry),
        Fragment => Some(shade::Stage::Pixel),

        _ => None,
    }
}

fn map_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Name { ref name, .. } => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_member_name_by_id<'a>(module: &'a spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Option<&'a str> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberName { ref name, member, .. } if member == member_id => {
                Some(&name[..])
            },
            _ => None,
        }
    }).next()
}

fn map_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::Decorate { ref decoration, .. } => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_member_decorations_by_id(module: &spirv_utils::RawModule, id: desc::Id, member_id: u32) -> Vec<instruction::Decoration> {
    module.uses(id).filter_map(|instr| {
        match *instr {
            instruction::Instruction::MemberDecorate { ref decoration, member, .. } if member == member_id => {
                Some(decoration.clone())
            },
            // TODO: GroupDecorations
            _ => None,
        }
    }).collect::<Vec<_>>()
}

fn map_image_to_texture_type(dim: desc::Dim, arrayed: bool, multisampled: bool) -> TextureType {
    use spirv_utils::desc::Dim;
    let arrayed = if arrayed { shade::IsArray::Array } else { shade::IsArray::NoArray };
    let multisampled = if multisampled { shade::IsMultiSample::MultiSample } else { shade::IsMultiSample::NoMultiSample };
    match dim {
        Dim::_1D => shade::TextureType::D1(arrayed),
        Dim::_2D => shade::TextureType::D2(arrayed, multisampled),
        Dim::_3D => shade::TextureType::D3,
        Dim::Cube => shade::TextureType::Cube(arrayed),
        Dim::Buffer => shade::TextureType::Buffer,

        _ => unimplemented!(),
    }
}

fn map_scalar_to_basetype(instr: &instruction::Instruction) -> Option<BaseType> {
    use spirv_utils::instruction::Instruction;
    match *instr {
        Instruction::TypeBool { .. } => Some(BaseType::Bool),
        Instruction::TypeInt { width: 32, signed: false, .. } => Some(BaseType::U32),
        Instruction::TypeInt { width: 32, signed: true, .. } => Some(BaseType::I32),
        Instruction::TypeFloat { width: 32, ..} => Some(BaseType::F32),
        Instruction::TypeFloat { width: 64, ..} => Some(BaseType::F64),

        _ => None,
    }
}

fn map_instruction_to_type(module: &spirv_utils::RawModule, instr: &instruction::Instruction) -> Option<Type> {
    use spirv_utils::instruction::{Decoration, Instruction};
    let id_ty = match *instr {
        Instruction::TypeBool { result_type } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: false } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeInt { result_type, width: 32, signed: true } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 32 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeFloat { result_type, width: 64 } => {
            Some((result_type, Ty::Basic(map_scalar_to_basetype(instr).unwrap(), ContainerType::Single)))
        },
        Instruction::TypeVector { result_type, type_id, len } => {
            let comp_ty = module.def(type_id).unwrap();
            Some((result_type, Ty::Basic(map_scalar_to_basetype(comp_ty).unwrap(), ContainerType::Vector(len as u8))))
        },
        Instruction::TypeMatrix { result_type, type_id, cols } => {
            let (base, rows) = match *module.def(type_id).unwrap() {
                Instruction::TypeVector { type_id, len, .. } => {
                    let comp_ty = module.def(type_id).unwrap();
                    (map_scalar_to_basetype(comp_ty).unwrap(), len)
                },
                _ => unreachable!(), // SPIR-V module would be invalid
            };

            let decoration = map_decorations_by_id(&module, result_type.into());

            // NOTE: temporary value, changes might be needed later depending on the decorations of the variable
            let matrix_format = if decoration.iter().find(|deco| **deco == Decoration::RowMajor).is_some() {
                shade::MatrixFormat::RowMajor
            } else {
                shade::MatrixFormat::ColumnMajor
            };

            Some((result_type, Ty::Basic(base, ContainerType::Matrix(matrix_format, rows as u8, cols as u8))))
        },
        Instruction::TypeStruct { result_type, ref fields } => {
            Some((
                result_type,
                Ty::Struct(
                    fields.iter().filter_map(|field| // TODO: should be `map()`, currently to ignore unsupported types
                        map_instruction_to_type(module, module.def(*field).unwrap())
                    ).collect::<Vec<_>>()
                )
            ))
        },
        Instruction::TypeSampler { result_type } => {
            Some((result_type, Ty::Sampler))
        },
        Instruction::TypeImage { result_type, type_id, dim, arrayed, multisampled, .. } => {
            Some((result_type, Ty::Image(map_scalar_to_basetype(module.def(type_id).unwrap()).unwrap(), map_image_to_texture_type(dim, arrayed, multisampled))))
        },

        _ => None,
    };

    id_ty.map(|(id, ty)| Type {
            id: id.into(),
            ty: ty,
            decoration: map_decorations_by_id(&module, id.into()),
        })
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SpirvReflection {
    entry_points: Vec<EntryPoint>,
    variables: Vec<Variable>,
    types: Vec<Type>,
}

pub fn reflect_spirv_module(code: &[u8]) -> SpirvReflection {
    use spirv_utils::instruction::Instruction;

    let module = spirv_utils::RawModule::read_module(code).expect("Unable to parse SPIR-V module");

    let mut entry_points = Vec::new();
    let mut variables = Vec::new();
    let mut types = Vec::new();
    for instr in module.instructions() {
        match *instr {
            Instruction::EntryPoint { execution_model, ref name, ref interface, .. } => {
                if let Some(stage) = map_execution_model_to_stage(execution_model) {
                    entry_points.push(EntryPoint {
                        name: name.clone(),
                        stage: stage,
                        interface: interface.clone(),
                    });
                } else {
                    error!("Unsupported execution model: {:?}", execution_model);
                }
            },
            Instruction::Variable { result_type, result_id, storage_class, .. } => {
                let decoration = map_decorations_by_id(&module, result_id.into());
                let ty = {
                    // remove indirection layer as the type of every variable is a OpTypePointer
                    let ptr_ty = module.def::<desc::TypeId>(result_type.into()).unwrap();
                    match *ptr_ty {
                        Instruction::TypePointer { ref pointee, .. } => *pointee,
                        _ => unreachable!(), // SPIR-V module would be invalid
                    }
                };

                // Every variable MUST have an name annotation
                // `glslang` seems to emit empty strings for uniforms with struct type,
                // therefore we need to retrieve the name from the struct decl
                let name = {
                    let name = map_name_by_id(&module, result_id.into()).expect("Missing name annotation");
                    if name.is_empty() {
                        map_name_by_id(&module, ty.into()).expect("Missing name annotation")
                    } else {
                        name
                    }
                };

                variables.push(Variable {
                    id: result_id.into(),
                    name: name.into(),
                    ty: ty.into(),
                    storage_class: storage_class,
                    decoration: decoration,
                });
            },

            _ => {
                // Reflect types, if we have OpTypeXXX
                if let Some(ty) = map_instruction_to_type(&module, instr) {
                    types.push(ty);
                }
            },
        }
    }

    SpirvReflection {
        entry_points: entry_points,
        variables: variables,
        types: types,
    }
}

pub fn populate_info(info: &mut shade::ProgramInfo, stage: shade::Stage, reflection: &SpirvReflection) {
    if stage == shade::Stage::Vertex {
        // record vertex attributes
        let entry_point = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage).expect("Couln't find entry point!");
        for attrib in entry_point.interface.iter() {
            if let Some(var) = reflection.variables.iter().find(|var| var.id == *attrib) {
                if var.storage_class == desc::StorageClass::Input {
                    let attrib_name = var.name.clone();
                    let slot = var.decoration.iter()
                                     .find(|dec| if let &instruction::Decoration::Location(..) = *dec { true } else { false })
                                     .map(|dec| if let instruction::Decoration::Location(slot) = *dec { Some(slot) } else { None })
                                     .expect("Missing location decoration").unwrap();
                    let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                    if let Ty::Basic(base, container) = ty.ty {
                        info.vertex_attributes.push(shade::AttributeVar {
                            name: attrib_name,
                            slot: slot as core::AttributeSlot,
                            base_type: base,
                            container: container,
                        });
                    } else {
                        error!("Unsupported type as vertex attribute: {:?}", ty.ty);
                    }
                }
            } else {
                error!("Missing vertex attribute reflection: {:?}", attrib);
            }
        }
    } else if stage == shade::Stage::Pixel {
        // record pixel outputs
        if let Some(entry_point) = reflection.entry_points.iter().find(|ep| ep.name == "main" && ep.stage == stage) {
            for out in entry_point.interface.iter() {
                if let Some(var) = reflection.variables.iter().find(|var| var.id == *out) {
                    if var.storage_class == desc::StorageClass::Output {
                        let target_name = var.name.clone();
                        let slot = var.decoration.iter()
                                         .find(|dec| if let &instruction::Decoration::Location(..) = *dec { true } else { false })
                                         .map(|dec| if let instruction::Decoration::Location(slot) = *dec { Some(slot) } else { None })
                                         .expect("Missing location decoration").unwrap();
                        let ty = reflection.types.iter().find(|ty| ty.id == var.ty).unwrap();
                        if let Ty::Basic(base, container) = ty.ty {
                            info.outputs.push(shade::OutputVar {
                                name: target_name,
                                slot: slot as core::ColorSlot,
                                base_type: base,
                                container: container,
                            });
                        } else {
                            error!("Unsupported type as pixel shader output: {:?}", ty.ty);
                        }
                    }
                } else {
                    error!("Missing pixel shader output reflection: {:?}", out);
                }
            }
        }
    }

    // Handle resources
    // We use only one descriptor set currently
    for var in reflection.variables.iter() {
        use spirv_utils::desc::StorageClass::*;
        match var.storage_class {
            Uniform | UniformConstant => {
                if let Some(ty) = reflection.types.iter().find(|ty| ty.id == var.ty) {
                    // constant buffers
                    match ty.ty {
                        Ty::Struct(ref fields) => {
                            let mut elements = Vec::new();
                            for field in fields {
                                // TODO:
                            }

                            let buffer_name = var.name.clone();
                            let slot = var.decoration.iter()
                                             .find(|dec| if let &instruction::Decoration::Binding(..) = *dec { true } else { false })
                                             .map(|dec| if let instruction::Decoration::Binding(slot) = *dec { Some(slot) } else { None })
                                             .expect("Missing binding decoration").unwrap();
                            info.constant_buffers.push(shade::ConstantBufferVar {
                                name: buffer_name,
                                slot: slot as core::ConstantBufferSlot,
                                size: 0, // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                                elements: elements,
                            });
                        },

                        Ty::Sampler => {
                            let sampler_name = var.name.trim_right_matches('_');
                            let slot = var.decoration.iter()
                                             .find(|dec| if let &instruction::Decoration::Binding(..) = *dec { true } else { false })
                                             .map(|dec| if let instruction::Decoration::Binding(slot) = *dec { Some(slot) } else { None })
                                             .expect("Missing binding decoration").unwrap();
                            info.samplers.push(shade::SamplerVar {
                                name: sampler_name.to_owned(),
                                slot: slot as core::SamplerSlot,
                                ty: shade::SamplerType(shade::IsComparison::NoCompare, shade::IsRect::NoRect), // TODO:
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        Ty::Image(base_type, texture_type) => {
                            let texture_name = var.name.clone();
                            let slot = var.decoration.iter()
                                             .find(|dec| if let &instruction::Decoration::Binding(..) = *dec { true } else { false })
                                             .map(|dec| if let instruction::Decoration::Binding(slot) = *dec { Some(slot) } else { None })
                                             .expect("Missing binding decoration").unwrap();
                            info.textures.push(shade::TextureVar {
                                name: texture_name,
                                slot: slot as core::ResourceViewSlot,
                                base_type: base_type,
                                ty: texture_type,
                                usage: shade::VERTEX | shade::GEOMETRY | shade::PIXEL, // TODO:
                            });
                        },

                        _ => (),
                    }
                } else {
                    error!("Unsupported uniform type: {:?}", var.ty);
                }
            },
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>fix deadlock when using debugger step command<commit_after><|endoftext|>


<commit_before><commit_msg>epoll_wait<commit_after><|endoftext|>


<commit_before><commit_msg>	modified:   dr-daemon.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Add an initializer to start the app.<commit_after>use getopts::{getopts};
use help;

fn verify_command(command: &str) -> bool {
    match command {
        "new"  => true,
        "open" => true,
        _      => false
    }
}

fn run_command(command: &str) {
    println!("{}", command);
}

pub fn init(args: Vec<String>) {
    let program = args[0].clone();
    let opts = help::opts();

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_string()) }
    };

    if matches.opt_present("h") {
        help::print_usage(program.as_slice(), opts);
        return;
    }

    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        help::print_usage(program.as_slice(), opts);
        return;
    };

    if !verify_command(input.as_slice()) {
      return;
    }

    run_command(input.as_slice());
}
<|endoftext|>


<commit_before><commit_msg>first try<commit_after>type Deadlock = Option<uint>;

static mut lock: Deadlock = None;
static mut anotherLock: Deadlock = None;

fn grab_lock(id: uint) {
    unsafe {
	while (lock.is_some()) {
	    ;
	}
	lock = Some(id);
    }
}

fn grab_anotherLock(id: uint) {
    unsafe {
	while (anotherLock.is_some()) {
	    ;
	}
	anotherLock = Some(id);
    }
}

fn release_lock() {
    unsafe {
	lock = None;
    }
}

fn release_anotherLock() {
    unsafe {
	anotherLock = None;
    }
}

fn update_process_1(id: uint) {
    unsafe {
	//while (update(id + 1) != id + 1) {
	  //  ;
	//}
	grab_anotherLock(id);
	println("Process 1 grabbed lock 2");
	release_lock();
    }
}

fn update_process_2(id: uint) {
    grab_lock(id);
    println("Process 2 grabbed lock 1");
    release_anotherLock();
}

fn main() {
    grab_lock(1);
    grab_anotherLock(2);
    do spawn {
	update_process_1(1);
	update_process_2(2);
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove redundant import<commit_after><|endoftext|>