<commit_before>extern crate c_ares_sys;

use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData;
use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use std::os::raw::{
    c_char,
    c_int,
};
use std::slice;
use std::str;

use c_types;

use types::AddressFamily;
use utils::address_family;

#[derive(Debug)]
pub struct HostentOwned {
    inner: *mut c_types::hostent,
    phantom: PhantomData<c_types::hostent>,
}

impl HostentOwned {
    pub fn new(hostent: *mut c_types::hostent) -> HostentOwned {
        HostentOwned {
            inner: hostent,
            phantom: PhantomData,
        }
    }
}

impl Drop for HostentOwned {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_hostent(
                self.inner as *mut c_ares_sys::hostent);
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct HostentBorrowed<'a> {
    inner: *const c_types::hostent,
    phantom: PhantomData<&'a c_types::hostent>,
}

impl<'a> HostentBorrowed<'a> {
    pub fn new(hostent: *const c_types::hostent) -> HostentBorrowed<'a> {
        HostentBorrowed {
            inner: hostent,
            phantom: PhantomData,
        }
    }
}

pub trait HasHostent {
    fn hostent(&self) -> &c_types::hostent;

    fn hostname(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(self.hostent().h_name);
            str::from_utf8_unchecked(c_str.to_bytes())
        }
    }

    fn addresses(&self) -> HostAddressResultsIter {
        HostAddressResultsIter {
            family: address_family(self.hostent().h_addrtype as c_int),
            next: self.hostent().h_addr_list as *const *const _,
            phantom: PhantomData,
        }
    }

    fn aliases(&self) -> HostAliasResultsIter {
        HostAliasResultsIter {
            next: self.hostent().h_aliases as *const *const _,
            phantom: PhantomData,
        }
    }

    fn display(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "Hostname: {}, ", self.hostname()));
        try!(write!(fmt, "Addresses: ["));
        let mut first = true;
        for host_addr in self.addresses() {
            let prefix = if first { "" } else { ", " };
            first = false;
            try!(write!(fmt, "{}{}", prefix, host_addr));
        }
        try!(write!(fmt, "], "));
        try!(write!(fmt, "Aliases: ["));
        let mut first = true;
        for host_alias in self.aliases() {
            let prefix = if first { "" } else { ", " };
            first = false;
            try!(write!(fmt, "{}{}", prefix, host_alias));
        }
        try!(write!(fmt, "]"));
        Ok(())
    }
}

impl HasHostent for HostentOwned {
    fn hostent(&self) -> &c_types::hostent {
        unsafe { &*self.inner }
    }
}

impl<'a> HasHostent for HostentBorrowed<'a> {
    fn hostent(&self) -> &c_types::hostent {
        unsafe { &*self.inner }
    }
}

unsafe impl Send for HostentOwned { }
unsafe impl Sync for HostentOwned { }

unsafe impl<'a> Send for HostentBorrowed<'a> { }
unsafe impl<'a> Sync for HostentBorrowed<'a> { }

/// Iterator of `IpAddr`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAddressResultsIter<'a> {
    family: Option<AddressFamily>,
    next: *const *const c_char,
    phantom: PhantomData<&'a c_types::hostent>,
}

// Get an IpAddr from a family and an array of bytes, as found in a `hostent`.
unsafe fn ip_address_from_bytes(
    family: AddressFamily,
    h_addr: *const u8) -> IpAddr {
    match family {
        AddressFamily::INET => {
            let source = slice::from_raw_parts(h_addr, 4);
            let mut bytes = [0u8; 4];
            bytes.copy_from_slice(source);
            let ipv4 = Ipv4Addr::from(bytes);
            IpAddr::V4(ipv4)
        },
        AddressFamily::INET6 => {
            let source = slice::from_raw_parts(h_addr, 16);
            let mut bytes = [0u8; 16];
            bytes.copy_from_slice(source);
            let ipv6 = Ipv6Addr::from(bytes);
            IpAddr::V6(ipv6)
        },
    }
}

impl<'a> Iterator for HostAddressResultsIter<'a> {
    type Item = IpAddr;
    fn next(&mut self) -> Option<Self::Item> {
        let h_addr = unsafe { *self.next };
        if h_addr.is_null() {
            None
        } else {
            unsafe {
                self.next = self.next.offset(1);
                self.family.map(|family| {
                    ip_address_from_bytes(family, h_addr as *const u8)
                })
            }
        }
    }
}

unsafe impl<'a> Send for HostAddressResultsIter<'a> { }
unsafe impl<'a> Sync for HostAddressResultsIter<'a> { }

/// Iterator of `&'a str`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAliasResultsIter<'a> {
    next: *const *const c_char,
    phantom: PhantomData<&'a c_types::hostent>,
}

impl<'a> Iterator for HostAliasResultsIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        let h_alias = unsafe { *self.next };
        if h_alias.is_null() {
            None
        } else {
            unsafe {
                self.next = self.next.offset(1);
                let c_str = CStr::from_ptr(h_alias);
                Some(str::from_utf8_unchecked(c_str.to_bytes()))
            }
        }
    }
}

unsafe impl<'a> Send for HostAliasResultsIter<'a> { }
unsafe impl<'a> Sync for HostAliasResultsIter<'a> { }
<commit_msg>Micro-optimisation<commit_after>extern crate c_ares_sys;

use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use std::os::raw::{
    c_char,
    c_int,
};
use std::slice;
use std::str;

use c_types;

use types::AddressFamily;
use utils::address_family;

#[derive(Debug)]
pub struct HostentOwned {
    inner: *mut c_types::hostent,
    phantom: PhantomData<c_types::hostent>,
}

impl HostentOwned {
    pub fn new(hostent: *mut c_types::hostent) -> HostentOwned {
        HostentOwned {
            inner: hostent,
            phantom: PhantomData,
        }
    }
}

impl Drop for HostentOwned {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_hostent(
                self.inner as *mut c_ares_sys::hostent);
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct HostentBorrowed<'a> {
    inner: *const c_types::hostent,
    phantom: PhantomData<&'a c_types::hostent>,
}

impl<'a> HostentBorrowed<'a> {
    pub fn new(hostent: *const c_types::hostent) -> HostentBorrowed<'a> {
        HostentBorrowed {
            inner: hostent,
            phantom: PhantomData,
        }
    }
}

pub trait HasHostent {
    fn hostent(&self) -> &c_types::hostent;

    fn hostname(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(self.hostent().h_name);
            str::from_utf8_unchecked(c_str.to_bytes())
        }
    }

    fn addresses(&self) -> HostAddressResultsIter {
        HostAddressResultsIter {
            family: address_family(self.hostent().h_addrtype as c_int),
            next: self.hostent().h_addr_list as *const *const _,
            phantom: PhantomData,
        }
    }

    fn aliases(&self) -> HostAliasResultsIter {
        HostAliasResultsIter {
            next: self.hostent().h_aliases as *const *const _,
            phantom: PhantomData,
        }
    }

    fn display(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "Hostname: {}, ", self.hostname()));
        try!(write!(fmt, "Addresses: ["));
        let mut first = true;
        for host_addr in self.addresses() {
            let prefix = if first { "" } else { ", " };
            first = false;
            try!(write!(fmt, "{}{}", prefix, host_addr));
        }
        try!(write!(fmt, "], "));
        try!(write!(fmt, "Aliases: ["));
        let mut first = true;
        for host_alias in self.aliases() {
            let prefix = if first { "" } else { ", " };
            first = false;
            try!(write!(fmt, "{}{}", prefix, host_alias));
        }
        try!(write!(fmt, "]"));
        Ok(())
    }
}

impl HasHostent for HostentOwned {
    fn hostent(&self) -> &c_types::hostent {
        unsafe { &*self.inner }
    }
}

impl<'a> HasHostent for HostentBorrowed<'a> {
    fn hostent(&self) -> &c_types::hostent {
        unsafe { &*self.inner }
    }
}

unsafe impl Send for HostentOwned { }
unsafe impl Sync for HostentOwned { }

unsafe impl<'a> Send for HostentBorrowed<'a> { }
unsafe impl<'a> Sync for HostentBorrowed<'a> { }

/// Iterator of `IpAddr`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAddressResultsIter<'a> {
    family: Option<AddressFamily>,
    next: *const *const c_char,
    phantom: PhantomData<&'a c_types::hostent>,
}

// Get an IpAddr from a family and an array of bytes, as found in a `hostent`.
unsafe fn ip_address_from_bytes(
    family: AddressFamily,
    h_addr: *const u8) -> IpAddr {
    match family {
        AddressFamily::INET => {
            let source = slice::from_raw_parts(h_addr, 4);
            let mut bytes: [u8; 4] = mem::uninitialized();
            bytes.copy_from_slice(source);
            let ipv4 = Ipv4Addr::from(bytes);
            IpAddr::V4(ipv4)
        },
        AddressFamily::INET6 => {
            let source = slice::from_raw_parts(h_addr, 16);
            let mut bytes: [u8; 16] = mem::uninitialized();
            bytes.copy_from_slice(source);
            let ipv6 = Ipv6Addr::from(bytes);
            IpAddr::V6(ipv6)
        },
    }
}

impl<'a> Iterator for HostAddressResultsIter<'a> {
    type Item = IpAddr;
    fn next(&mut self) -> Option<Self::Item> {
        let h_addr = unsafe { *self.next };
        if h_addr.is_null() {
            None
        } else {
            unsafe {
                self.next = self.next.offset(1);
                self.family.map(|family| {
                    ip_address_from_bytes(family, h_addr as *const u8)
                })
            }
        }
    }
}

unsafe impl<'a> Send for HostAddressResultsIter<'a> { }
unsafe impl<'a> Sync for HostAddressResultsIter<'a> { }

/// Iterator of `&'a str`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAliasResultsIter<'a> {
    next: *const *const c_char,
    phantom: PhantomData<&'a c_types::hostent>,
}

impl<'a> Iterator for HostAliasResultsIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        let h_alias = unsafe { *self.next };
        if h_alias.is_null() {
            None
        } else {
            unsafe {
                self.next = self.next.offset(1);
                let c_str = CStr::from_ptr(h_alias);
                Some(str::from_utf8_unchecked(c_str.to_bytes()))
            }
        }
    }
}

unsafe impl<'a> Send for HostAliasResultsIter<'a> { }
unsafe impl<'a> Sync for HostAliasResultsIter<'a> { }
<|endoftext|>


<commit_before>use regex::{Regex, Captures};
use rustc_serialize::json::Json;

use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};

use command::{WebDriverCommand, WebDriverMessage, WebDriverExtensionCommand,
              VoidWebDriverExtensionCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};

fn standard_routes<U:WebDriverExtensionRoute>() -> Vec<(Method, &'static str, Route<U>)> {
    return vec![(Post, "/session", Route::NewSession),
                (Delete, "/session/{sessionId}", Route::DeleteSession),
                (Post, "/session/{sessionId}/url", Route::Get),
                (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
                (Post, "/session/{sessionId}/back", Route::GoBack),
                (Post, "/session/{sessionId}/forward", Route::GoForward),
                (Post, "/session/{sessionId}/refresh", Route::Refresh),
                (Get, "/session/{sessionId}/title", Route::GetTitle),
                (Get, "/session/{sessionId}/source", Route::GetPageSource),
                (Get, "/session/{sessionId}/window", Route::GetWindowHandle),
                (Get, "/session/{sessionId}/window/handles", Route::GetWindowHandles),
                (Delete, "/session/{sessionId}/window", Route::CloseWindow),
                (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
                (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
                (Get, "/session/{sessionId}/window/position", Route::GetWindowPosition),
                (Post, "/session/{sessionId}/window/position", Route::SetWindowPosition),
                (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
                (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
                (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
                (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
                (Post, "/session/{sessionId}/element", Route::FindElement),
                (Post, "/session/{sessionId}/elements", Route::FindElements),
                (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement),
                (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements),
                (Get, "/session/{sessionId}/element/active", Route::GetActiveElement),
                (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
                (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
                (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
                (Get, "/session/{sessionId}/element/{elementId}/property/{name}", Route::GetElementProperty),
                (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
                (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
                (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
                (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
                (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
                (Post, "/session/{sessionId}/execute/sync", Route::ExecuteScript),
                (Post, "/session/{sessionId}/execute/async", Route::ExecuteAsyncScript),
                (Get, "/session/{sessionId}/cookie", Route::GetCookies),
                (Get, "/session/{sessionId}/cookie/{name}", Route::GetNamedCookie),
                (Post, "/session/{sessionId}/cookie", Route::AddCookie),
                (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies),
                (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie),
                (Get, "/session/{sessionId}/timeouts", Route::GetTimeouts),
                (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
                (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
                (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
                (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
                (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys),
                (Post, "/session/{sessionId}/alert/dismiss", Route::DismissAlert),
                (Post, "/session/{sessionId}/alert/accept", Route::AcceptAlert),
                (Get, "/session/{sessionId}/alert/text", Route::GetAlertText),
                (Post, "/session/{sessionId}/alert/text", Route::SendAlertText),
                (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot),
                (Get, "/session/{sessionId}/element/{elementId}/screenshot", Route::TakeElementScreenshot),
                (Post, "/session/{sessionId}/actions", Route::PerformActions),
                (Delete, "/session/{sessionId}/actions", Route::ReleaseActions),
                (Get, "/status", Route::Status),]
}

#[derive(Clone, Copy)]
pub enum Route<U:WebDriverExtensionRoute> {
    NewSession,
    DeleteSession,
    Get,
    GetCurrentUrl,
    GoBack,
    GoForward,
    Refresh,
    GetTitle,
    GetPageSource,
    GetWindowHandle,
    GetWindowHandles,
    CloseWindow,
    GetWindowSize,
    SetWindowSize,
    GetWindowPosition,
    SetWindowPosition,
    MaximizeWindow,
    SwitchToWindow,
    SwitchToFrame,
    SwitchToParentFrame,
    FindElement,
    FindElements,
    FindElementElement,
    FindElementElements,
    GetActiveElement,
    IsDisplayed,
    IsSelected,
    GetElementAttribute,
    GetElementProperty,
    GetCSSValue,
    GetElementText,
    GetElementTagName,
    GetElementRect,
    IsEnabled,
    ExecuteScript,
    ExecuteAsyncScript,
    GetCookies,
    GetNamedCookie,
    AddCookie,
    DeleteCookies,
    DeleteCookie,
    GetTimeouts,
    SetTimeouts,
    ElementClick,
    ElementTap,
    ElementClear,
    ElementSendKeys,
    PerformActions,
    ReleaseActions,
    DismissAlert,
    AcceptAlert,
    GetAlertText,
    SendAlertText,
    TakeScreenshot,
    TakeElementScreenshot,
    Status,
    Extension(U),
}

pub trait WebDriverExtensionRoute : Clone + Send + PartialEq {
    type Command: WebDriverExtensionCommand + 'static;

    fn command(&self, &Captures, &Json) -> WebDriverResult<WebDriverCommand<Self::Command>>;
}

#[derive(Clone, PartialEq)]
pub struct VoidWebDriverExtensionRoute;

impl WebDriverExtensionRoute for VoidWebDriverExtensionRoute {
    type Command = VoidWebDriverExtensionCommand;

    fn command(&self, _:&Captures, _:&Json) -> WebDriverResult<WebDriverCommand<VoidWebDriverExtensionCommand>> {
        panic!("No extensions implemented");
    }
}

#[derive(Clone)]
struct RequestMatcher<U: WebDriverExtensionRoute> {
    method: Method,
    path_regexp: Regex,
    match_type: Route<U>
}

impl <U: WebDriverExtensionRoute> RequestMatcher<U> {
    pub fn new(method: Method, path: &str, match_type: Route<U>) -> RequestMatcher<U> {
        let path_regexp = RequestMatcher::<U>::compile_path(path);
        RequestMatcher {
            method: method,
            path_regexp: path_regexp,
            match_type: match_type
        }
    }

    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
        let captures = self.path_regexp.captures(path);
        (method == self.method, captures)
    }

    fn compile_path(path: &str) -> Regex {
        let mut rv = String::new();
        rv.push_str("^");
        let components = path.split('/');
        for component in components {
            if component.starts_with("{") {
                if !component.ends_with("}") {
                    panic!("Invalid url pattern")
                }
                rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
            } else {
                rv.push_str(&format!("{}/", component)[..]);
            }
        }
        //Remove the trailing /
        rv.pop();
        rv.push_str("$");
        //This will fail at runtime if the regexp is invalid
        Regex::new(&rv[..]).unwrap()
    }
}

pub struct WebDriverHttpApi<U: WebDriverExtensionRoute> {
    routes: Vec<(Method, RequestMatcher<U>)>,
}

impl <U: WebDriverExtensionRoute> WebDriverHttpApi<U> {
    pub fn new(extension_routes: &[(Method, &str, U)]) -> WebDriverHttpApi<U> {
        let mut rv = WebDriverHttpApi::<U> {
            routes: vec![],
        };
        debug!("Creating routes");
        for &(ref method, ref url, ref match_type) in standard_routes::<U>().iter() {
            rv.add(method.clone(), *url, (*match_type).clone());
        };
        for &(ref method, ref url, ref extension_route) in extension_routes.iter() {
            rv.add(method.clone(), *url, Route::Extension(extension_route.clone()));
        };
        rv
    }

    fn add(&mut self, method: Method, path: &str, match_type: Route<U>) {
        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
        self.routes.push((method, http_matcher));
    }

    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage<U>> {
        let mut error = ErrorStatus::UnknownPath;
        for &(ref match_method, ref matcher) in self.routes.iter() {
            if method == *match_method {
                let (method_match, captures) = matcher.get_match(method.clone(), path);
                if captures.is_some() {
                    if method_match {
                        return WebDriverMessage::from_http(matcher.match_type.clone(),
                                                           &captures.unwrap(),
                                                           body,
                                                           method == Post)
                    } else {
                        error = ErrorStatus::UnknownMethod;
                    }
                }
            }
        }
        Err(WebDriverError::new(error,
                                format!("{} {} did not match a known command", method, path)))
    }
}
<commit_msg>httpapi: add GetWindowRect and SetWindowRect routes<commit_after>use regex::{Regex, Captures};
use rustc_serialize::json::Json;

use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};

use command::{WebDriverCommand, WebDriverMessage, WebDriverExtensionCommand,
              VoidWebDriverExtensionCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};

fn standard_routes<U:WebDriverExtensionRoute>() -> Vec<(Method, &'static str, Route<U>)> {
    return vec![(Post, "/session", Route::NewSession),
                (Delete, "/session/{sessionId}", Route::DeleteSession),
                (Post, "/session/{sessionId}/url", Route::Get),
                (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
                (Post, "/session/{sessionId}/back", Route::GoBack),
                (Post, "/session/{sessionId}/forward", Route::GoForward),
                (Post, "/session/{sessionId}/refresh", Route::Refresh),
                (Get, "/session/{sessionId}/title", Route::GetTitle),
                (Get, "/session/{sessionId}/source", Route::GetPageSource),
                (Get, "/session/{sessionId}/window", Route::GetWindowHandle),
                (Get, "/session/{sessionId}/window/handles", Route::GetWindowHandles),
                (Delete, "/session/{sessionId}/window", Route::CloseWindow),
                (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
                (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
                (Get, "/session/{sessionId}/window/position", Route::GetWindowPosition),
                (Post, "/session/{sessionId}/window/position", Route::SetWindowPosition),
                (Get, "/session/{sessionId}/window/rect", Route::GetWindowRect),
                (Post, "/session/{sessionId}/window/rect", Route::SetWindowRect),
                (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
                (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
                (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
                (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
                (Post, "/session/{sessionId}/element", Route::FindElement),
                (Post, "/session/{sessionId}/elements", Route::FindElements),
                (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement),
                (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements),
                (Get, "/session/{sessionId}/element/active", Route::GetActiveElement),
                (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
                (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
                (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
                (Get, "/session/{sessionId}/element/{elementId}/property/{name}", Route::GetElementProperty),
                (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
                (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
                (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
                (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
                (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
                (Post, "/session/{sessionId}/execute/sync", Route::ExecuteScript),
                (Post, "/session/{sessionId}/execute/async", Route::ExecuteAsyncScript),
                (Get, "/session/{sessionId}/cookie", Route::GetCookies),
                (Get, "/session/{sessionId}/cookie/{name}", Route::GetNamedCookie),
                (Post, "/session/{sessionId}/cookie", Route::AddCookie),
                (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies),
                (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie),
                (Get, "/session/{sessionId}/timeouts", Route::GetTimeouts),
                (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
                (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
                (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
                (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
                (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys),
                (Post, "/session/{sessionId}/alert/dismiss", Route::DismissAlert),
                (Post, "/session/{sessionId}/alert/accept", Route::AcceptAlert),
                (Get, "/session/{sessionId}/alert/text", Route::GetAlertText),
                (Post, "/session/{sessionId}/alert/text", Route::SendAlertText),
                (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot),
                (Get, "/session/{sessionId}/element/{elementId}/screenshot", Route::TakeElementScreenshot),
                (Post, "/session/{sessionId}/actions", Route::PerformActions),
                (Delete, "/session/{sessionId}/actions", Route::ReleaseActions),
                (Get, "/status", Route::Status),]
}

#[derive(Clone, Copy)]
pub enum Route<U:WebDriverExtensionRoute> {
    NewSession,
    DeleteSession,
    Get,
    GetCurrentUrl,
    GoBack,
    GoForward,
    Refresh,
    GetTitle,
    GetPageSource,
    GetWindowHandle,
    GetWindowHandles,
    CloseWindow,
    GetWindowSize,  // deprecated
    SetWindowSize,  // deprecated
    GetWindowPosition,  // deprecated
    SetWindowPosition,  // deprecated
    GetWindowRect,
    SetWindowRect,
    MaximizeWindow,
    SwitchToWindow,
    SwitchToFrame,
    SwitchToParentFrame,
    FindElement,
    FindElements,
    FindElementElement,
    FindElementElements,
    GetActiveElement,
    IsDisplayed,
    IsSelected,
    GetElementAttribute,
    GetElementProperty,
    GetCSSValue,
    GetElementText,
    GetElementTagName,
    GetElementRect,
    IsEnabled,
    ExecuteScript,
    ExecuteAsyncScript,
    GetCookies,
    GetNamedCookie,
    AddCookie,
    DeleteCookies,
    DeleteCookie,
    GetTimeouts,
    SetTimeouts,
    ElementClick,
    ElementTap,
    ElementClear,
    ElementSendKeys,
    PerformActions,
    ReleaseActions,
    DismissAlert,
    AcceptAlert,
    GetAlertText,
    SendAlertText,
    TakeScreenshot,
    TakeElementScreenshot,
    Status,
    Extension(U),
}

pub trait WebDriverExtensionRoute : Clone + Send + PartialEq {
    type Command: WebDriverExtensionCommand + 'static;

    fn command(&self, &Captures, &Json) -> WebDriverResult<WebDriverCommand<Self::Command>>;
}

#[derive(Clone, PartialEq)]
pub struct VoidWebDriverExtensionRoute;

impl WebDriverExtensionRoute for VoidWebDriverExtensionRoute {
    type Command = VoidWebDriverExtensionCommand;

    fn command(&self, _:&Captures, _:&Json) -> WebDriverResult<WebDriverCommand<VoidWebDriverExtensionCommand>> {
        panic!("No extensions implemented");
    }
}

#[derive(Clone)]
struct RequestMatcher<U: WebDriverExtensionRoute> {
    method: Method,
    path_regexp: Regex,
    match_type: Route<U>
}

impl <U: WebDriverExtensionRoute> RequestMatcher<U> {
    pub fn new(method: Method, path: &str, match_type: Route<U>) -> RequestMatcher<U> {
        let path_regexp = RequestMatcher::<U>::compile_path(path);
        RequestMatcher {
            method: method,
            path_regexp: path_regexp,
            match_type: match_type
        }
    }

    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
        let captures = self.path_regexp.captures(path);
        (method == self.method, captures)
    }

    fn compile_path(path: &str) -> Regex {
        let mut rv = String::new();
        rv.push_str("^");
        let components = path.split('/');
        for component in components {
            if component.starts_with("{") {
                if !component.ends_with("}") {
                    panic!("Invalid url pattern")
                }
                rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
            } else {
                rv.push_str(&format!("{}/", component)[..]);
            }
        }
        //Remove the trailing /
        rv.pop();
        rv.push_str("$");
        //This will fail at runtime if the regexp is invalid
        Regex::new(&rv[..]).unwrap()
    }
}

pub struct WebDriverHttpApi<U: WebDriverExtensionRoute> {
    routes: Vec<(Method, RequestMatcher<U>)>,
}

impl <U: WebDriverExtensionRoute> WebDriverHttpApi<U> {
    pub fn new(extension_routes: &[(Method, &str, U)]) -> WebDriverHttpApi<U> {
        let mut rv = WebDriverHttpApi::<U> {
            routes: vec![],
        };
        debug!("Creating routes");
        for &(ref method, ref url, ref match_type) in standard_routes::<U>().iter() {
            rv.add(method.clone(), *url, (*match_type).clone());
        };
        for &(ref method, ref url, ref extension_route) in extension_routes.iter() {
            rv.add(method.clone(), *url, Route::Extension(extension_route.clone()));
        };
        rv
    }

    fn add(&mut self, method: Method, path: &str, match_type: Route<U>) {
        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
        self.routes.push((method, http_matcher));
    }

    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage<U>> {
        let mut error = ErrorStatus::UnknownPath;
        for &(ref match_method, ref matcher) in self.routes.iter() {
            if method == *match_method {
                let (method_match, captures) = matcher.get_match(method.clone(), path);
                if captures.is_some() {
                    if method_match {
                        return WebDriverMessage::from_http(matcher.match_type.clone(),
                                                           &captures.unwrap(),
                                                           body,
                                                           method == Post)
                    } else {
                        error = ErrorStatus::UnknownMethod;
                    }
                }
            }
        }
        Err(WebDriverError::new(error,
                                format!("{} {} did not match a known command", method, path)))
    }
}
<|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/. */

//! This module contains shared types and messages for use by devtools/script.
//! The traits are here instead of in script so that the devtools crate can be
//! modified independently of the rest of Servo.

#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]

#![allow(non_snake_case)]
#![deny(unsafe_code)]

#![feature(proc_macro)]

#[allow(unused_extern_crates)]
#[macro_use]
extern crate bitflags;
extern crate heapsize;
#[macro_use] extern crate heapsize_derive;
extern crate hyper;
extern crate ipc_channel;
extern crate msg;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate time;
extern crate url;

use hyper::header::Headers;
use hyper::method::Method;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use std::net::TcpStream;
use time::Duration;
use time::Tm;
use url::Url;

// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
#[derive(Deserialize, Serialize)]
pub struct DevtoolsPageInfo {
    pub title: String,
    pub url: Url
}

#[derive(Deserialize, HeapSizeOf, Serialize, Clone)]
pub struct CSSError {
    pub filename: String,
    pub line: usize,
    pub column: usize,
    pub msg: String
}

/// Messages to instruct the devtools server to update its known actors/state
/// according to changes in the browser.
pub enum DevtoolsControlMsg {
    /// Messages from threads in the chrome process (resource/constellation/devtools)
    FromChrome(ChromeToDevtoolsControlMsg),
    /// Messages from script threads
    FromScript(ScriptToDevtoolsControlMsg),
}

/// Events that the devtools server must act upon.
pub enum ChromeToDevtoolsControlMsg {
    /// A new client has connected to the server.
    AddClient(TcpStream),
    /// The browser is shutting down.
    ServerExitMsg,
    /// A network event occurred (request, reply, etc.). The actor with the
    /// provided name should be notified.
    NetworkEvent(String, NetworkEvent),
}

#[derive(Deserialize, Serialize)]
/// Events that the devtools server must act upon.
pub enum ScriptToDevtoolsControlMsg {
    /// A new global object was created, associated with a particular pipeline.
    /// The means of communicating directly with it are provided.
    NewGlobal((PipelineId, Option<WorkerId>),
              IpcSender<DevtoolScriptControlMsg>,
              DevtoolsPageInfo),
    /// A particular page has invoked the console API.
    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
    /// An animation frame with the given timestamp was processed in a script thread.
    /// The actor with the provided name should be notified.
    FramerateTick(String, f64),

    /// Report a CSS parse error for the given pipeline
    ReportCSSError(PipelineId, CSSError),
}

/// Serialized JS return values
/// TODO: generalize this beyond the EvaluateJS message?
#[derive(Deserialize, Serialize)]
pub enum EvaluateJSReply {
    VoidValue,
    NullValue,
    BooleanValue(bool),
    NumberValue(f64),
    StringValue(String),
    ActorValue { class: String, uuid: String },
}

#[derive(Deserialize, Serialize)]
pub struct AttrInfo {
    pub namespace: String,
    pub name: String,
    pub value: String,
}

#[derive(Deserialize, Serialize)]
pub struct NodeInfo {
    pub uniqueId: String,
    pub baseURI: String,
    pub parent: String,
    pub nodeType: u16,
    pub namespaceURI: String,
    pub nodeName: String,
    pub numChildren: usize,

    pub name: String,
    pub publicId: String,
    pub systemId: String,

    pub attrs: Vec<AttrInfo>,

    pub isDocumentElement: bool,

    pub shortValue: String,
    pub incompleteValue: bool,
}

pub struct StartedTimelineMarker {
    name: String,
    start_time: PreciseTime,
    start_stack: Option<Vec<()>>,
}

#[derive(Deserialize, Serialize)]
pub struct TimelineMarker {
    pub name: String,
    pub start_time: PreciseTime,
    pub start_stack: Option<Vec<()>>,
    pub end_time: PreciseTime,
    pub end_stack: Option<Vec<()>>,
}

#[derive(PartialEq, Eq, Hash, Clone, Deserialize, Serialize, HeapSizeOf)]
pub enum TimelineMarkerType {
    Reflow,
    DOMEvent,
}

/// The properties of a DOM node as computed by layout.
#[derive(Deserialize, Serialize)]
pub struct ComputedNodeLayout {
    pub display: String,
    pub position: String,
    pub zIndex: String,
    pub boxSizing: String,

    pub autoMargins: AutoMargins,
    pub marginTop: String,
    pub marginRight: String,
    pub marginBottom: String,
    pub marginLeft: String,

    pub borderTopWidth: String,
    pub borderRightWidth: String,
    pub borderBottomWidth: String,
    pub borderLeftWidth: String,

    pub paddingTop: String,
    pub paddingRight: String,
    pub paddingBottom: String,
    pub paddingLeft: String,

    pub width: f32,
    pub height: f32,
}

#[derive(Deserialize, Serialize)]
pub struct AutoMargins {
    pub top: bool,
    pub right: bool,
    pub bottom: bool,
    pub left: bool,
}

/// Messages to process in a particular script thread, as instructed by a devtools client.
/// TODO: better error handling, e.g. if pipeline id lookup fails?
#[derive(Deserialize, Serialize)]
pub enum DevtoolScriptControlMsg {
    /// Evaluate a JS snippet in the context of the global for the given pipeline.
    EvaluateJS(PipelineId, String, IpcSender<EvaluateJSReply>),
    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
    GetRootNode(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the document element for the given pipeline.
    GetDocumentElement(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the child nodes of the given node in the given pipeline.
    GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>),
    /// Retrieve the computed layout properties of the given node in the given pipeline.
    GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>),
    /// Retrieve all stored console messages for the given pipeline.
    GetCachedMessages(PipelineId, CachedConsoleMessageTypes, IpcSender<Vec<CachedConsoleMessage>>),
    /// Update a given node's attributes with a list of modifications.
    ModifyAttribute(PipelineId, String, Vec<Modification>),
    /// Request live console messages for a given pipeline (true if desired, false otherwise).
    WantsLiveNotifications(PipelineId, bool),
    /// Request live notifications for a given set of timeline events for a given pipeline.
    SetTimelineMarkers(PipelineId, Vec<TimelineMarkerType>, IpcSender<Option<TimelineMarker>>),
    /// Withdraw request for live timeline notifications for a given pipeline.
    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
    /// Request a callback directed at the given actor name from the next animation frame
    /// executed in the given pipeline.
    RequestAnimationFrame(PipelineId, String),
    /// Direct the given pipeline to reload the current page.
    Reload(PipelineId),
}

#[derive(Deserialize, Serialize)]
pub struct Modification {
    pub attributeName: String,
    pub newValue: Option<String>,
}

#[derive(Clone, Deserialize, Serialize)]
pub enum LogLevel {
    Log,
    Debug,
    Info,
    Warn,
    Error,
}

#[derive(Clone, Deserialize, Serialize)]
pub struct ConsoleMessage {
    pub message: String,
    pub logLevel: LogLevel,
    pub filename: String,
    pub lineNumber: usize,
    pub columnNumber: usize,
}

bitflags! {
    #[derive(Deserialize, Serialize)]
    pub flags CachedConsoleMessageTypes: u8 {
        const PAGE_ERROR  = 1 << 0,
        const CONSOLE_API = 1 << 1,
    }
}

#[derive(Deserialize, Serialize)]
pub struct PageError {
    #[serde(rename = "_type")]
    pub type_: String,
    pub errorMessage: String,
    pub sourceName: String,
    pub lineText: String,
    pub lineNumber: u32,
    pub columnNumber: u32,
    pub category: String,
    pub timeStamp: u64,
    pub error: bool,
    pub warning: bool,
    pub exception: bool,
    pub strict: bool,
    pub private: bool,
}

#[derive(Deserialize, Serialize)]
pub struct ConsoleAPI {
    #[serde(rename = "_type")]
    pub type_: String,
    pub level: String,
    pub filename: String,
    pub lineNumber: u32,
    pub functionName: String,
    pub timeStamp: u64,
    pub private: bool,
    pub arguments: Vec<String>,
}

#[derive(Deserialize, Serialize)]
pub enum CachedConsoleMessage {
    PageError(PageError),
    ConsoleAPI(ConsoleAPI),
}

#[derive(Debug, PartialEq)]
pub struct HttpRequest {
    pub url: Url,
    pub method: Method,
    pub headers: Headers,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
    pub startedDateTime: Tm,
    pub timeStamp: i64,
    pub connect_time: u64,
    pub send_time: u64,
    pub is_xhr: bool,
}

#[derive(Debug, PartialEq)]
pub struct HttpResponse {
    pub headers: Option<Headers>,
    pub status: Option<(u16, Vec<u8>)>,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
}

pub enum NetworkEvent {
    HttpRequest(HttpRequest),
    HttpResponse(HttpResponse),
}

impl TimelineMarker {
    pub fn start(name: String) -> StartedTimelineMarker {
        StartedTimelineMarker {
            name: name,
            start_time: PreciseTime::now(),
            start_stack: None,
        }
    }
}

impl StartedTimelineMarker {
    pub fn end(self) -> TimelineMarker {
        TimelineMarker {
            name: self.name,
            start_time: self.start_time,
            start_stack: self.start_stack,
            end_time: PreciseTime::now(),
            end_stack: None,
        }
    }
}

/// A replacement for `time::PreciseTime` that isn't opaque, so we can serialize it.
///
/// The reason why this doesn't go upstream is that `time` is slated to be part of Rust's standard
/// library, which definitely can't have any dependencies on `serde`. But `serde` can't implement
/// `Deserialize` and `Serialize` itself, because `time::PreciseTime` is opaque! A Catch-22. So I'm
/// duplicating the definition here.
#[derive(Copy, Clone, Deserialize, Serialize)]
pub struct PreciseTime(u64);

impl PreciseTime {
    pub fn now() -> PreciseTime {
        PreciseTime(time::precise_time_ns())
    }

    pub fn to(&self, later: PreciseTime) -> Duration {
        Duration::nanoseconds((later.0 - self.0) as i64)
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct WorkerId(pub u32);
<commit_msg>Auto merge of #14132 - servo:debug-devtools, r=jdm<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/. */

//! This module contains shared types and messages for use by devtools/script.
//! The traits are here instead of in script so that the devtools crate can be
//! modified independently of the rest of Servo.

#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]

#![allow(non_snake_case)]
#![deny(unsafe_code)]

#![feature(proc_macro)]

#[allow(unused_extern_crates)]
#[macro_use]
extern crate bitflags;
extern crate heapsize;
#[macro_use] extern crate heapsize_derive;
extern crate hyper;
extern crate ipc_channel;
extern crate msg;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate time;
extern crate url;

use hyper::header::Headers;
use hyper::method::Method;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use std::net::TcpStream;
use time::Duration;
use time::Tm;
use url::Url;

// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
#[derive(Debug, Deserialize, Serialize)]
pub struct DevtoolsPageInfo {
    pub title: String,
    pub url: Url
}

#[derive(Debug, Deserialize, HeapSizeOf, Serialize, Clone)]
pub struct CSSError {
    pub filename: String,
    pub line: usize,
    pub column: usize,
    pub msg: String
}

/// Messages to instruct the devtools server to update its known actors/state
/// according to changes in the browser.
#[derive(Debug)]
pub enum DevtoolsControlMsg {
    /// Messages from threads in the chrome process (resource/constellation/devtools)
    FromChrome(ChromeToDevtoolsControlMsg),
    /// Messages from script threads
    FromScript(ScriptToDevtoolsControlMsg),
}

/// Events that the devtools server must act upon.
#[derive(Debug)]
pub enum ChromeToDevtoolsControlMsg {
    /// A new client has connected to the server.
    AddClient(TcpStream),
    /// The browser is shutting down.
    ServerExitMsg,
    /// A network event occurred (request, reply, etc.). The actor with the
    /// provided name should be notified.
    NetworkEvent(String, NetworkEvent),
}

#[derive(Debug, Deserialize, Serialize)]
/// Events that the devtools server must act upon.
pub enum ScriptToDevtoolsControlMsg {
    /// A new global object was created, associated with a particular pipeline.
    /// The means of communicating directly with it are provided.
    NewGlobal((PipelineId, Option<WorkerId>),
              IpcSender<DevtoolScriptControlMsg>,
              DevtoolsPageInfo),
    /// A particular page has invoked the console API.
    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
    /// An animation frame with the given timestamp was processed in a script thread.
    /// The actor with the provided name should be notified.
    FramerateTick(String, f64),

    /// Report a CSS parse error for the given pipeline
    ReportCSSError(PipelineId, CSSError),
}

/// Serialized JS return values
/// TODO: generalize this beyond the EvaluateJS message?
#[derive(Debug, Deserialize, Serialize)]
pub enum EvaluateJSReply {
    VoidValue,
    NullValue,
    BooleanValue(bool),
    NumberValue(f64),
    StringValue(String),
    ActorValue { class: String, uuid: String },
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AttrInfo {
    pub namespace: String,
    pub name: String,
    pub value: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct NodeInfo {
    pub uniqueId: String,
    pub baseURI: String,
    pub parent: String,
    pub nodeType: u16,
    pub namespaceURI: String,
    pub nodeName: String,
    pub numChildren: usize,

    pub name: String,
    pub publicId: String,
    pub systemId: String,

    pub attrs: Vec<AttrInfo>,

    pub isDocumentElement: bool,

    pub shortValue: String,
    pub incompleteValue: bool,
}

pub struct StartedTimelineMarker {
    name: String,
    start_time: PreciseTime,
    start_stack: Option<Vec<()>>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TimelineMarker {
    pub name: String,
    pub start_time: PreciseTime,
    pub start_stack: Option<Vec<()>>,
    pub end_time: PreciseTime,
    pub end_stack: Option<Vec<()>>,
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize, HeapSizeOf)]
pub enum TimelineMarkerType {
    Reflow,
    DOMEvent,
}

/// The properties of a DOM node as computed by layout.
#[derive(Debug, Deserialize, Serialize)]
pub struct ComputedNodeLayout {
    pub display: String,
    pub position: String,
    pub zIndex: String,
    pub boxSizing: String,

    pub autoMargins: AutoMargins,
    pub marginTop: String,
    pub marginRight: String,
    pub marginBottom: String,
    pub marginLeft: String,

    pub borderTopWidth: String,
    pub borderRightWidth: String,
    pub borderBottomWidth: String,
    pub borderLeftWidth: String,

    pub paddingTop: String,
    pub paddingRight: String,
    pub paddingBottom: String,
    pub paddingLeft: String,

    pub width: f32,
    pub height: f32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AutoMargins {
    pub top: bool,
    pub right: bool,
    pub bottom: bool,
    pub left: bool,
}

/// Messages to process in a particular script thread, as instructed by a devtools client.
/// TODO: better error handling, e.g. if pipeline id lookup fails?
#[derive(Debug, Deserialize, Serialize)]
pub enum DevtoolScriptControlMsg {
    /// Evaluate a JS snippet in the context of the global for the given pipeline.
    EvaluateJS(PipelineId, String, IpcSender<EvaluateJSReply>),
    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
    GetRootNode(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the document element for the given pipeline.
    GetDocumentElement(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the child nodes of the given node in the given pipeline.
    GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>),
    /// Retrieve the computed layout properties of the given node in the given pipeline.
    GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>),
    /// Retrieve all stored console messages for the given pipeline.
    GetCachedMessages(PipelineId, CachedConsoleMessageTypes, IpcSender<Vec<CachedConsoleMessage>>),
    /// Update a given node's attributes with a list of modifications.
    ModifyAttribute(PipelineId, String, Vec<Modification>),
    /// Request live console messages for a given pipeline (true if desired, false otherwise).
    WantsLiveNotifications(PipelineId, bool),
    /// Request live notifications for a given set of timeline events for a given pipeline.
    SetTimelineMarkers(PipelineId, Vec<TimelineMarkerType>, IpcSender<Option<TimelineMarker>>),
    /// Withdraw request for live timeline notifications for a given pipeline.
    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
    /// Request a callback directed at the given actor name from the next animation frame
    /// executed in the given pipeline.
    RequestAnimationFrame(PipelineId, String),
    /// Direct the given pipeline to reload the current page.
    Reload(PipelineId),
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Modification {
    pub attributeName: String,
    pub newValue: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum LogLevel {
    Log,
    Debug,
    Info,
    Warn,
    Error,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ConsoleMessage {
    pub message: String,
    pub logLevel: LogLevel,
    pub filename: String,
    pub lineNumber: usize,
    pub columnNumber: usize,
}

bitflags! {
    #[derive(Deserialize, Serialize)]
    pub flags CachedConsoleMessageTypes: u8 {
        const PAGE_ERROR  = 1 << 0,
        const CONSOLE_API = 1 << 1,
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct PageError {
    #[serde(rename = "_type")]
    pub type_: String,
    pub errorMessage: String,
    pub sourceName: String,
    pub lineText: String,
    pub lineNumber: u32,
    pub columnNumber: u32,
    pub category: String,
    pub timeStamp: u64,
    pub error: bool,
    pub warning: bool,
    pub exception: bool,
    pub strict: bool,
    pub private: bool,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ConsoleAPI {
    #[serde(rename = "_type")]
    pub type_: String,
    pub level: String,
    pub filename: String,
    pub lineNumber: u32,
    pub functionName: String,
    pub timeStamp: u64,
    pub private: bool,
    pub arguments: Vec<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub enum CachedConsoleMessage {
    PageError(PageError),
    ConsoleAPI(ConsoleAPI),
}

#[derive(Debug, PartialEq)]
pub struct HttpRequest {
    pub url: Url,
    pub method: Method,
    pub headers: Headers,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
    pub startedDateTime: Tm,
    pub timeStamp: i64,
    pub connect_time: u64,
    pub send_time: u64,
    pub is_xhr: bool,
}

#[derive(Debug, PartialEq)]
pub struct HttpResponse {
    pub headers: Option<Headers>,
    pub status: Option<(u16, Vec<u8>)>,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
}

#[derive(Debug)]
pub enum NetworkEvent {
    HttpRequest(HttpRequest),
    HttpResponse(HttpResponse),
}

impl TimelineMarker {
    pub fn start(name: String) -> StartedTimelineMarker {
        StartedTimelineMarker {
            name: name,
            start_time: PreciseTime::now(),
            start_stack: None,
        }
    }
}

impl StartedTimelineMarker {
    pub fn end(self) -> TimelineMarker {
        TimelineMarker {
            name: self.name,
            start_time: self.start_time,
            start_stack: self.start_stack,
            end_time: PreciseTime::now(),
            end_stack: None,
        }
    }
}

/// A replacement for `time::PreciseTime` that isn't opaque, so we can serialize it.
///
/// The reason why this doesn't go upstream is that `time` is slated to be part of Rust's standard
/// library, which definitely can't have any dependencies on `serde`. But `serde` can't implement
/// `Deserialize` and `Serialize` itself, because `time::PreciseTime` is opaque! A Catch-22. So I'm
/// duplicating the definition here.
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
pub struct PreciseTime(u64);

impl PreciseTime {
    pub fn now() -> PreciseTime {
        PreciseTime(time::precise_time_ns())
    }

    pub fn to(&self, later: PreciseTime) -> Duration {
        Duration::nanoseconds((later.0 - self.0) as i64)
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct WorkerId(pub u32);
<|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/. */

//! This module contains shared types and messages for use by devtools/script.
//! The traits are here instead of in script so that the devtools crate can be
//! modified independently of the rest of Servo.

#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]

#![allow(non_snake_case)]
#![deny(unsafe_code)]

#![feature(custom_derive, plugin)]
#![plugin(heapsize_plugin, serde_macros)]

#[allow(unused_extern_crates)]
#[macro_use]
extern crate bitflags;
extern crate heapsize;
extern crate hyper;
extern crate ipc_channel;
extern crate msg;
extern crate serde;
extern crate time;
extern crate url;

use hyper::header::Headers;
use hyper::method::Method;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use std::net::TcpStream;
use time::Duration;
use time::Tm;
use url::Url;

// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
#[derive(Deserialize, Serialize)]
pub struct DevtoolsPageInfo {
    pub title: String,
    pub url: Url
}

#[derive(Deserialize, HeapSizeOf, Serialize, Clone)]
pub struct CSSError {
    pub filename: String,
    pub line: usize,
    pub column: usize,
    pub msg: String
}

/// Messages to instruct the devtools server to update its known actors/state
/// according to changes in the browser.
pub enum DevtoolsControlMsg {
    /// Messages from threads in the chrome process (resource/constellation/devtools)
    FromChrome(ChromeToDevtoolsControlMsg),
    /// Messages from script threads
    FromScript(ScriptToDevtoolsControlMsg),
}

/// Events that the devtools server must act upon.
pub enum ChromeToDevtoolsControlMsg {
    /// A new client has connected to the server.
    AddClient(TcpStream),
    /// The browser is shutting down.
    ServerExitMsg,
    /// A network event occurred (request, reply, etc.). The actor with the
    /// provided name should be notified.
    NetworkEvent(String, NetworkEvent),
}

#[derive(Deserialize, Serialize)]
/// Events that the devtools server must act upon.
pub enum ScriptToDevtoolsControlMsg {
    /// A new global object was created, associated with a particular pipeline.
    /// The means of communicating directly with it are provided.
    NewGlobal((PipelineId, Option<WorkerId>),
              IpcSender<DevtoolScriptControlMsg>,
              DevtoolsPageInfo),
    /// A particular page has invoked the console API.
    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
    /// An animation frame with the given timestamp was processed in a script thread.
    /// The actor with the provided name should be notified.
    FramerateTick(String, f64),

    /// Report a CSS parse error for the given pipeline
    ReportCSSError(PipelineId, CSSError),
}

/// Serialized JS return values
/// TODO: generalize this beyond the EvaluateJS message?
#[derive(Deserialize, Serialize)]
pub enum EvaluateJSReply {
    VoidValue,
    NullValue,
    BooleanValue(bool),
    NumberValue(f64),
    StringValue(String),
    ActorValue { class: String, uuid: String },
}

#[derive(Deserialize, Serialize)]
pub struct AttrInfo {
    pub namespace: String,
    pub name: String,
    pub value: String,
}

#[derive(Deserialize, Serialize)]
pub struct NodeInfo {
    pub uniqueId: String,
    pub baseURI: String,
    pub parent: String,
    pub nodeType: u16,
    pub namespaceURI: String,
    pub nodeName: String,
    pub numChildren: usize,

    pub name: String,
    pub publicId: String,
    pub systemId: String,

    pub attrs: Vec<AttrInfo>,

    pub isDocumentElement: bool,

    pub shortValue: String,
    pub incompleteValue: bool,
}

pub struct StartedTimelineMarker {
    name: String,
    start_time: PreciseTime,
    start_stack: Option<Vec<()>>,
}

#[derive(Deserialize, Serialize)]
pub struct TimelineMarker {
    pub name: String,
    pub start_time: PreciseTime,
    pub start_stack: Option<Vec<()>>,
    pub end_time: PreciseTime,
    pub end_stack: Option<Vec<()>>,
}

#[derive(PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub enum TimelineMarkerType {
    Reflow,
    DOMEvent,
}

/// The properties of a DOM node as computed by layout.
#[derive(Deserialize, Serialize)]
pub struct ComputedNodeLayout {
    pub display: String,
    pub position: String,
    pub zIndex: String,
    pub boxSizing: String,

    pub autoMargins: AutoMargins,
    pub marginTop: String,
    pub marginRight: String,
    pub marginBottom: String,
    pub marginLeft: String,

    pub borderTopWidth: String,
    pub borderRightWidth: String,
    pub borderBottomWidth: String,
    pub borderLeftWidth: String,

    pub paddingTop: String,
    pub paddingRight: String,
    pub paddingBottom: String,
    pub paddingLeft: String,

    pub width: f32,
    pub height: f32,
}

#[derive(Deserialize, Serialize)]
pub struct AutoMargins {
    pub top: bool,
    pub right: bool,
    pub bottom: bool,
    pub left: bool,
}

/// Messages to process in a particular script thread, as instructed by a devtools client.
#[derive(Deserialize, Serialize)]
pub enum DevtoolScriptControlMsg {
    /// Evaluate a JS snippet in the context of the global for the given pipeline.
    EvaluateJS(PipelineId, String, IpcSender<EvaluateJSReply>),
    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
    GetRootNode(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the document element for the given pipeline.
    GetDocumentElement(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the child nodes of the given node in the given pipeline.
    GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>),
    /// Retrieve the computed layout properties of the given node in the given pipeline.
    GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>),
    /// Retrieve all stored console messages for the given pipeline.
    GetCachedMessages(PipelineId, CachedConsoleMessageTypes, IpcSender<Vec<CachedConsoleMessage>>),
    /// Update a given node's attributes with a list of modifications.
    ModifyAttribute(PipelineId, String, Vec<Modification>),
    /// Request live console messages for a given pipeline (true if desired, false otherwise).
    WantsLiveNotifications(PipelineId, bool),
    /// Request live notifications for a given set of timeline events for a given pipeline.
    SetTimelineMarkers(PipelineId, Vec<TimelineMarkerType>, IpcSender<TimelineMarker>),
    /// Withdraw request for live timeline notifications for a given pipeline.
    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
    /// Request a callback directed at the given actor name from the next animation frame
    /// executed in the given pipeline.
    RequestAnimationFrame(PipelineId, String),
    /// Direct the given pipeline to reload the current page.
    Reload(PipelineId),
}

#[derive(Deserialize, Serialize)]
pub struct Modification {
    pub attributeName: String,
    pub newValue: Option<String>,
}

#[derive(Clone, Deserialize, Serialize)]
pub enum LogLevel {
    Log,
    Debug,
    Info,
    Warn,
    Error,
}

#[derive(Clone, Deserialize, Serialize)]
pub struct ConsoleMessage {
    pub message: String,
    pub logLevel: LogLevel,
    pub filename: String,
    pub lineNumber: usize,
    pub columnNumber: usize,
}

bitflags! {
    #[derive(Deserialize, Serialize)]
    pub flags CachedConsoleMessageTypes: u8 {
        const PAGE_ERROR  = 1 << 0,
        const CONSOLE_API = 1 << 1,
    }
}

#[derive(Deserialize, Serialize)]
pub struct PageError {
    #[serde(rename = "_type")]
    pub type_: String,
    pub errorMessage: String,
    pub sourceName: String,
    pub lineText: String,
    pub lineNumber: u32,
    pub columnNumber: u32,
    pub category: String,
    pub timeStamp: u64,
    pub error: bool,
    pub warning: bool,
    pub exception: bool,
    pub strict: bool,
    pub private: bool,
}

#[derive(Deserialize, Serialize)]
pub struct ConsoleAPI {
    #[serde(rename = "_type")]
    pub type_: String,
    pub level: String,
    pub filename: String,
    pub lineNumber: u32,
    pub functionName: String,
    pub timeStamp: u64,
    pub private: bool,
    pub arguments: Vec<String>,
}

#[derive(Deserialize, Serialize)]
pub enum CachedConsoleMessage {
    PageError(PageError),
    ConsoleAPI(ConsoleAPI),
}

#[derive(Debug, PartialEq)]
pub struct HttpRequest {
    pub url: Url,
    pub method: Method,
    pub headers: Headers,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
    pub startedDateTime: Tm,
    pub timeStamp: i64,
    pub connect_time: u64,
    pub send_time: u64,
    pub is_xhr: bool,
}

#[derive(Debug, PartialEq)]
pub struct HttpResponse {
    pub headers: Option<Headers>,
    pub status: Option<(u16, Vec<u8>)>,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
}

pub enum NetworkEvent {
    HttpRequest(HttpRequest),
    HttpResponse(HttpResponse),
}

impl TimelineMarker {
    pub fn start(name: String) -> StartedTimelineMarker {
        StartedTimelineMarker {
            name: name,
            start_time: PreciseTime::now(),
            start_stack: None,
        }
    }
}

impl StartedTimelineMarker {
    pub fn end(self) -> TimelineMarker {
        TimelineMarker {
            name: self.name,
            start_time: self.start_time,
            start_stack: self.start_stack,
            end_time: PreciseTime::now(),
            end_stack: None,
        }
    }
}

/// A replacement for `time::PreciseTime` that isn't opaque, so we can serialize it.
///
/// The reason why this doesn't go upstream is that `time` is slated to be part of Rust's standard
/// library, which definitely can't have any dependencies on `serde`. But `serde` can't implement
/// `Deserialize` and `Serialize` itself, because `time::PreciseTime` is opaque! A Catch-22. So I'm
/// duplicating the definition here.
#[derive(Copy, Clone, Deserialize, Serialize)]
pub struct PreciseTime(u64);

impl PreciseTime {
    pub fn now() -> PreciseTime {
        PreciseTime(time::precise_time_ns())
    }

    pub fn to(&self, later: PreciseTime) -> Duration {
        Duration::nanoseconds((later.0 - self.0) as i64)
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct WorkerId(pub u32);
<commit_msg>Derive the HeapSizeOf on TimelineMarkerType<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/. */

//! This module contains shared types and messages for use by devtools/script.
//! The traits are here instead of in script so that the devtools crate can be
//! modified independently of the rest of Servo.

#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]

#![allow(non_snake_case)]
#![deny(unsafe_code)]

#![feature(custom_derive, plugin)]
#![plugin(heapsize_plugin, serde_macros)]

#[allow(unused_extern_crates)]
#[macro_use]
extern crate bitflags;
extern crate heapsize;
extern crate hyper;
extern crate ipc_channel;
extern crate msg;
extern crate serde;
extern crate time;
extern crate url;

use hyper::header::Headers;
use hyper::method::Method;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use std::net::TcpStream;
use time::Duration;
use time::Tm;
use url::Url;

// Information would be attached to NewGlobal to be received and show in devtools.
// Extend these fields if we need more information.
#[derive(Deserialize, Serialize)]
pub struct DevtoolsPageInfo {
    pub title: String,
    pub url: Url
}

#[derive(Deserialize, HeapSizeOf, Serialize, Clone)]
pub struct CSSError {
    pub filename: String,
    pub line: usize,
    pub column: usize,
    pub msg: String
}

/// Messages to instruct the devtools server to update its known actors/state
/// according to changes in the browser.
pub enum DevtoolsControlMsg {
    /// Messages from threads in the chrome process (resource/constellation/devtools)
    FromChrome(ChromeToDevtoolsControlMsg),
    /// Messages from script threads
    FromScript(ScriptToDevtoolsControlMsg),
}

/// Events that the devtools server must act upon.
pub enum ChromeToDevtoolsControlMsg {
    /// A new client has connected to the server.
    AddClient(TcpStream),
    /// The browser is shutting down.
    ServerExitMsg,
    /// A network event occurred (request, reply, etc.). The actor with the
    /// provided name should be notified.
    NetworkEvent(String, NetworkEvent),
}

#[derive(Deserialize, Serialize)]
/// Events that the devtools server must act upon.
pub enum ScriptToDevtoolsControlMsg {
    /// A new global object was created, associated with a particular pipeline.
    /// The means of communicating directly with it are provided.
    NewGlobal((PipelineId, Option<WorkerId>),
              IpcSender<DevtoolScriptControlMsg>,
              DevtoolsPageInfo),
    /// A particular page has invoked the console API.
    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
    /// An animation frame with the given timestamp was processed in a script thread.
    /// The actor with the provided name should be notified.
    FramerateTick(String, f64),

    /// Report a CSS parse error for the given pipeline
    ReportCSSError(PipelineId, CSSError),
}

/// Serialized JS return values
/// TODO: generalize this beyond the EvaluateJS message?
#[derive(Deserialize, Serialize)]
pub enum EvaluateJSReply {
    VoidValue,
    NullValue,
    BooleanValue(bool),
    NumberValue(f64),
    StringValue(String),
    ActorValue { class: String, uuid: String },
}

#[derive(Deserialize, Serialize)]
pub struct AttrInfo {
    pub namespace: String,
    pub name: String,
    pub value: String,
}

#[derive(Deserialize, Serialize)]
pub struct NodeInfo {
    pub uniqueId: String,
    pub baseURI: String,
    pub parent: String,
    pub nodeType: u16,
    pub namespaceURI: String,
    pub nodeName: String,
    pub numChildren: usize,

    pub name: String,
    pub publicId: String,
    pub systemId: String,

    pub attrs: Vec<AttrInfo>,

    pub isDocumentElement: bool,

    pub shortValue: String,
    pub incompleteValue: bool,
}

pub struct StartedTimelineMarker {
    name: String,
    start_time: PreciseTime,
    start_stack: Option<Vec<()>>,
}

#[derive(Deserialize, Serialize)]
pub struct TimelineMarker {
    pub name: String,
    pub start_time: PreciseTime,
    pub start_stack: Option<Vec<()>>,
    pub end_time: PreciseTime,
    pub end_stack: Option<Vec<()>>,
}

#[derive(PartialEq, Eq, Hash, Clone, Deserialize, Serialize, HeapSizeOf)]
pub enum TimelineMarkerType {
    Reflow,
    DOMEvent,
}

/// The properties of a DOM node as computed by layout.
#[derive(Deserialize, Serialize)]
pub struct ComputedNodeLayout {
    pub display: String,
    pub position: String,
    pub zIndex: String,
    pub boxSizing: String,

    pub autoMargins: AutoMargins,
    pub marginTop: String,
    pub marginRight: String,
    pub marginBottom: String,
    pub marginLeft: String,

    pub borderTopWidth: String,
    pub borderRightWidth: String,
    pub borderBottomWidth: String,
    pub borderLeftWidth: String,

    pub paddingTop: String,
    pub paddingRight: String,
    pub paddingBottom: String,
    pub paddingLeft: String,

    pub width: f32,
    pub height: f32,
}

#[derive(Deserialize, Serialize)]
pub struct AutoMargins {
    pub top: bool,
    pub right: bool,
    pub bottom: bool,
    pub left: bool,
}

/// Messages to process in a particular script thread, as instructed by a devtools client.
#[derive(Deserialize, Serialize)]
pub enum DevtoolScriptControlMsg {
    /// Evaluate a JS snippet in the context of the global for the given pipeline.
    EvaluateJS(PipelineId, String, IpcSender<EvaluateJSReply>),
    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
    GetRootNode(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the document element for the given pipeline.
    GetDocumentElement(PipelineId, IpcSender<Option<NodeInfo>>),
    /// Retrieve the details of the child nodes of the given node in the given pipeline.
    GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>),
    /// Retrieve the computed layout properties of the given node in the given pipeline.
    GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>),
    /// Retrieve all stored console messages for the given pipeline.
    GetCachedMessages(PipelineId, CachedConsoleMessageTypes, IpcSender<Vec<CachedConsoleMessage>>),
    /// Update a given node's attributes with a list of modifications.
    ModifyAttribute(PipelineId, String, Vec<Modification>),
    /// Request live console messages for a given pipeline (true if desired, false otherwise).
    WantsLiveNotifications(PipelineId, bool),
    /// Request live notifications for a given set of timeline events for a given pipeline.
    SetTimelineMarkers(PipelineId, Vec<TimelineMarkerType>, IpcSender<TimelineMarker>),
    /// Withdraw request for live timeline notifications for a given pipeline.
    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
    /// Request a callback directed at the given actor name from the next animation frame
    /// executed in the given pipeline.
    RequestAnimationFrame(PipelineId, String),
    /// Direct the given pipeline to reload the current page.
    Reload(PipelineId),
}

#[derive(Deserialize, Serialize)]
pub struct Modification {
    pub attributeName: String,
    pub newValue: Option<String>,
}

#[derive(Clone, Deserialize, Serialize)]
pub enum LogLevel {
    Log,
    Debug,
    Info,
    Warn,
    Error,
}

#[derive(Clone, Deserialize, Serialize)]
pub struct ConsoleMessage {
    pub message: String,
    pub logLevel: LogLevel,
    pub filename: String,
    pub lineNumber: usize,
    pub columnNumber: usize,
}

bitflags! {
    #[derive(Deserialize, Serialize)]
    pub flags CachedConsoleMessageTypes: u8 {
        const PAGE_ERROR  = 1 << 0,
        const CONSOLE_API = 1 << 1,
    }
}

#[derive(Deserialize, Serialize)]
pub struct PageError {
    #[serde(rename = "_type")]
    pub type_: String,
    pub errorMessage: String,
    pub sourceName: String,
    pub lineText: String,
    pub lineNumber: u32,
    pub columnNumber: u32,
    pub category: String,
    pub timeStamp: u64,
    pub error: bool,
    pub warning: bool,
    pub exception: bool,
    pub strict: bool,
    pub private: bool,
}

#[derive(Deserialize, Serialize)]
pub struct ConsoleAPI {
    #[serde(rename = "_type")]
    pub type_: String,
    pub level: String,
    pub filename: String,
    pub lineNumber: u32,
    pub functionName: String,
    pub timeStamp: u64,
    pub private: bool,
    pub arguments: Vec<String>,
}

#[derive(Deserialize, Serialize)]
pub enum CachedConsoleMessage {
    PageError(PageError),
    ConsoleAPI(ConsoleAPI),
}

#[derive(Debug, PartialEq)]
pub struct HttpRequest {
    pub url: Url,
    pub method: Method,
    pub headers: Headers,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
    pub startedDateTime: Tm,
    pub timeStamp: i64,
    pub connect_time: u64,
    pub send_time: u64,
    pub is_xhr: bool,
}

#[derive(Debug, PartialEq)]
pub struct HttpResponse {
    pub headers: Option<Headers>,
    pub status: Option<(u16, Vec<u8>)>,
    pub body: Option<Vec<u8>>,
    pub pipeline_id: PipelineId,
}

pub enum NetworkEvent {
    HttpRequest(HttpRequest),
    HttpResponse(HttpResponse),
}

impl TimelineMarker {
    pub fn start(name: String) -> StartedTimelineMarker {
        StartedTimelineMarker {
            name: name,
            start_time: PreciseTime::now(),
            start_stack: None,
        }
    }
}

impl StartedTimelineMarker {
    pub fn end(self) -> TimelineMarker {
        TimelineMarker {
            name: self.name,
            start_time: self.start_time,
            start_stack: self.start_stack,
            end_time: PreciseTime::now(),
            end_stack: None,
        }
    }
}

/// A replacement for `time::PreciseTime` that isn't opaque, so we can serialize it.
///
/// The reason why this doesn't go upstream is that `time` is slated to be part of Rust's standard
/// library, which definitely can't have any dependencies on `serde`. But `serde` can't implement
/// `Deserialize` and `Serialize` itself, because `time::PreciseTime` is opaque! A Catch-22. So I'm
/// duplicating the definition here.
#[derive(Copy, Clone, Deserialize, Serialize)]
pub struct PreciseTime(u64);

impl PreciseTime {
    pub fn now() -> PreciseTime {
        PreciseTime(time::precise_time_ns())
    }

    pub fn to(&self, later: PreciseTime) -> Duration {
        Duration::nanoseconds((later.0 - self.0) as i64)
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct WorkerId(pub u32);
<|endoftext|>


<commit_before>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use objc::runtime::{NO, YES};

#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLCompareFunction {
    Never = 0,
    Less = 1,
    Equal = 2,
    LessEqual = 3,
    Greater = 4,
    NotEqual = 5,
    GreaterEqual = 6,
    Always = 7,
}

#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLStencilOperation {
    Keep = 0,
    Zero = 1,
    Replace = 2,
    IncrementClamp = 3,
    DecrementClamp = 4,
    Invert = 5,
    IncrementWrap = 6,
    DecrementWrap = 7,
}

pub enum MTLStencilDescriptor {}

foreign_obj_type! {
    type CType = MTLStencilDescriptor;
    pub struct StencilDescriptor;
    pub struct StencilDescriptorRef;
}

impl StencilDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLStencilDescriptor);
            msg_send![class, new]
        }
    }
}

impl StencilDescriptorRef {
    pub fn stencil_compare_function(&self) -> MTLCompareFunction {
        unsafe { msg_send![self, stencilCompareFunction] }
    }

    pub fn set_stencil_compare_function(&self, func: MTLCompareFunction) {
        unsafe { msg_send![self, setStencilCompareFunction: func] }
    }

    pub fn stencil_failure_operation(&self) -> MTLStencilOperation {
        unsafe { msg_send![self, stencilFailureOperation] }
    }

    pub fn set_stencil_failure_operation(&self, operation: MTLStencilOperation) {
        unsafe { msg_send![self, setStencilFailureOperation: operation] }
    }

    pub fn depth_failure_operation(&self) -> MTLStencilOperation {
        unsafe { msg_send![self, depthFailureOperation] }
    }

    pub fn set_depth_failure_operation(&self, operation: MTLStencilOperation) {
        unsafe { msg_send![self, setDepthFailureOperation: operation] }
    }

    pub fn depth_stencil_pass_operation(&self) -> MTLStencilOperation {
        unsafe { msg_send![self, depthStencilPassOperation] }
    }

    pub fn set_depth_stencil_pass_operation(&self, operation: MTLStencilOperation) {
        unsafe { msg_send![self, setDepthStencilPassOperation: operation] }
    }

    pub fn read_mask(&self) -> u32 {
        unsafe { msg_send![self, readMask] }
    }

    pub fn set_read_mask(&self, mask: u32) {
        unsafe { msg_send![self, setReadMask: mask] }
    }

    pub fn write_mask(&self) -> u32 {
        unsafe { msg_send![self, writeMask] }
    }

    pub fn set_write_mask(&self, mask: u32) {
        unsafe { msg_send![self, setWriteMask: mask] }
    }
}

pub enum MTLDepthStencilDescriptor {}

foreign_obj_type! {
    type CType = MTLDepthStencilDescriptor;
    pub struct DepthStencilDescriptor;
    pub struct DepthStencilDescriptorRef;
}

impl DepthStencilDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLDepthStencilDescriptor);
            msg_send![class, new]
        }
    }
}

impl DepthStencilDescriptorRef {
    pub fn depth_compare_function(&self) -> MTLCompareFunction {
        unsafe { msg_send![self, depthCompareFunction] }
    }

    pub fn set_depth_compare_function(&self, func: MTLCompareFunction) {
        unsafe { msg_send![self, setDepthCompareFunction: func] }
    }

    pub fn depth_write_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, isDepthWriteEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_depth_write_enabled(&self, enabled: bool) {
        unsafe { msg_send![self, setDepthWriteEnabled: enabled] }
    }

    pub fn front_face_stencil(&self) -> Option<&StencilDescriptorRef> {
        unsafe { msg_send![self, frontFaceStencil] }
    }

    pub fn set_front_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) {
        unsafe { msg_send![self, setFrontFaceStencil: descriptor] }
    }

    pub fn back_face_stencil(&self) -> Option<&StencilDescriptorRef> {
        unsafe { msg_send![self, backFaceStencil] }
    }

    pub fn set_back_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) {
        unsafe { msg_send![self, setBackFaceStencil: descriptor] }
    }
}

pub enum MTLDepthStencilState {}

foreign_obj_type! {
    type CType = MTLDepthStencilState;
    pub struct DepthStencilState;
    pub struct DepthStencilStateRef;
}
<commit_msg>Nitpicks3 (#174)<commit_after>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::DeviceRef;
use objc::runtime::{NO, YES};

#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLCompareFunction {
    Never = 0,
    Less = 1,
    Equal = 2,
    LessEqual = 3,
    Greater = 4,
    NotEqual = 5,
    GreaterEqual = 6,
    Always = 7,
}

#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLStencilOperation {
    Keep = 0,
    Zero = 1,
    Replace = 2,
    IncrementClamp = 3,
    DecrementClamp = 4,
    Invert = 5,
    IncrementWrap = 6,
    DecrementWrap = 7,
}

pub enum MTLStencilDescriptor {}

foreign_obj_type! {
    type CType = MTLStencilDescriptor;
    pub struct StencilDescriptor;
    pub struct StencilDescriptorRef;
}

impl StencilDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLStencilDescriptor);
            msg_send![class, new]
        }
    }
}

impl StencilDescriptorRef {
    pub fn stencil_compare_function(&self) -> MTLCompareFunction {
        unsafe { msg_send![self, stencilCompareFunction] }
    }

    pub fn set_stencil_compare_function(&self, func: MTLCompareFunction) {
        unsafe { msg_send![self, setStencilCompareFunction: func] }
    }

    pub fn stencil_failure_operation(&self) -> MTLStencilOperation {
        unsafe { msg_send![self, stencilFailureOperation] }
    }

    pub fn set_stencil_failure_operation(&self, operation: MTLStencilOperation) {
        unsafe { msg_send![self, setStencilFailureOperation: operation] }
    }

    pub fn depth_failure_operation(&self) -> MTLStencilOperation {
        unsafe { msg_send![self, depthFailureOperation] }
    }

    pub fn set_depth_failure_operation(&self, operation: MTLStencilOperation) {
        unsafe { msg_send![self, setDepthFailureOperation: operation] }
    }

    pub fn depth_stencil_pass_operation(&self) -> MTLStencilOperation {
        unsafe { msg_send![self, depthStencilPassOperation] }
    }

    pub fn set_depth_stencil_pass_operation(&self, operation: MTLStencilOperation) {
        unsafe { msg_send![self, setDepthStencilPassOperation: operation] }
    }

    pub fn read_mask(&self) -> u32 {
        unsafe { msg_send![self, readMask] }
    }

    pub fn set_read_mask(&self, mask: u32) {
        unsafe { msg_send![self, setReadMask: mask] }
    }

    pub fn write_mask(&self) -> u32 {
        unsafe { msg_send![self, writeMask] }
    }

    pub fn set_write_mask(&self, mask: u32) {
        unsafe { msg_send![self, setWriteMask: mask] }
    }
}

pub enum MTLDepthStencilDescriptor {}

foreign_obj_type! {
    type CType = MTLDepthStencilDescriptor;
    pub struct DepthStencilDescriptor;
    pub struct DepthStencilDescriptorRef;
}

impl DepthStencilDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLDepthStencilDescriptor);
            msg_send![class, new]
        }
    }
}

impl DepthStencilDescriptorRef {
    pub fn depth_compare_function(&self) -> MTLCompareFunction {
        unsafe { msg_send![self, depthCompareFunction] }
    }

    pub fn set_depth_compare_function(&self, func: MTLCompareFunction) {
        unsafe { msg_send![self, setDepthCompareFunction: func] }
    }

    pub fn depth_write_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, isDepthWriteEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_depth_write_enabled(&self, enabled: bool) {
        unsafe { msg_send![self, setDepthWriteEnabled: enabled] }
    }

    pub fn front_face_stencil(&self) -> Option<&StencilDescriptorRef> {
        unsafe { msg_send![self, frontFaceStencil] }
    }

    pub fn set_front_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) {
        unsafe { msg_send![self, setFrontFaceStencil: descriptor] }
    }

    pub fn back_face_stencil(&self) -> Option<&StencilDescriptorRef> {
        unsafe { msg_send![self, backFaceStencil] }
    }

    pub fn set_back_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) {
        unsafe { msg_send![self, setBackFaceStencil: descriptor] }
    }

    pub fn label(&self) -> &str {
        unsafe {
            let label = msg_send![self, label];
            crate::nsstring_as_str(label)
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = crate::nsstring_from_str(label);
            let () = msg_send![self, setLabel: nslabel];
        }
    }
}

pub enum MTLDepthStencilState {}

foreign_obj_type! {
    type CType = MTLDepthStencilState;
    pub struct DepthStencilState;
    pub struct DepthStencilStateRef;
}

impl DepthStencilStateRef {
    pub fn device(&self) -> &DeviceRef {
        unsafe { msg_send![self, device] }
    }

    pub fn label(&self) -> &str {
        unsafe {
            let label = msg_send![self, label];
            crate::nsstring_as_str(label)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::str::FromStr;
use std::path::Path;
use std::io;
use std::fs;

use error::Result;

use hcore::crypto::init;
use hcore::package::PackageIdent;
use common::ui::{UI, Status};

const SCAFFOLDING_GO_IDENT: &'static str = "core/scaffolding-go";
const SCAFFOLDING_NODE_IDENT: &'static str = "core/scaffolding-node";
const SCAFFOLDING_RUBY_IDENT: &'static str = "core/scaffolding-ruby";

// Check to see if the --scaffolding passed matches available core scaffolding
// If not check if we've been given a pkg ident for a custom scaffolding
pub fn scaffold_check(ui: &mut UI, maybe_scaffold: Option<&str>) -> Result<Option<PackageIdent>> {
    match maybe_scaffold {
        Some(scaffold) => {
            init();
            match scaffold.to_lowercase().as_ref() {
                SCAFFOLDING_GO_IDENT |
                "go" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_GO_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Go Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                SCAFFOLDING_NODE_IDENT |
                "node" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_NODE_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Node Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                SCAFFOLDING_RUBY_IDENT |
                "ruby" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_RUBY_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Ruby Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                _ => {
                    let ident = PackageIdent::from_str(scaffold).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("custom Scaffolding: '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
            }
        }
        // If nothing was passed try to autodiscover the codebase
        // I'm not saying it's magic. But, MAGIC.
        None => autodiscover_scaffolding(ui),
    }
}
fn autodiscover_scaffolding(ui: &mut UI) -> Result<Option<PackageIdent>> {
    // Determine if the current dir has an app that can use
    // one of our scaffoldings and use it by default
    ui.begin("Attempting autodiscovery ")?;
    ui.para(
        "No scaffolding type was provided. Let's see if we can figure out \
        what kind of application you're planning to package.",
    )?;
    let current_path = Path::new(".");
    if is_project_go(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_GO_IDENT).unwrap();
        ui.begin("We've detected a Go codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else if is_project_node(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_NODE_IDENT).unwrap();
        ui.begin("We've detected a Node.js codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else if is_project_ruby(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_RUBY_IDENT).unwrap();
        ui.begin("We've detected a Ruby codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else {
        ui.warn(
            "Unable to determine the type of app in your current directory",
        )?;
        ui.para(
            "For now, we'll generate a plan with all of the available plan variables and build \
            phase callbacks. For more documentation on plan options try passing --withdocs \
            or visit https://www.habitat.sh/docs/reference/plan-syntax/",
        )?;
        Ok(None)
    }
}

fn is_project_go<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("main.go").is_file() ||
        path.as_ref().join("Godeps/Godeps.json").is_file() ||
        path.as_ref().join("vendor/vendor.json").is_file() ||
        path.as_ref().join("glide.yaml").is_file() ||
        project_uses_gb(path.as_ref()).expect("Result<bool> not returned from .go file check")
    {
        return true;
    }
    return false;
}

fn is_project_node<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("package.json").is_file() {
        return true;
    }
    return false;
}

fn is_project_ruby<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("Gemfile").is_file() {
        return true;
    }
    return false;
}

fn project_uses_gb(dir: &Path) -> io::Result<bool> {
    if dir.is_dir() {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                project_uses_gb(&path)?;
            } else if path.is_file() {
                if let Some(ext) = path.extension() {
                    if ext == "go" {
                        return Ok(true);
                    }
                }
            } else {
                return Ok(false);
            }
        }
    }
    return Ok(false);
}
<commit_msg>[hab] Add Gradle Scaffolding support to `hab plan init`.<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::str::FromStr;
use std::path::Path;
use std::io;
use std::fs;

use error::Result;

use hcore::crypto::init;
use hcore::package::PackageIdent;
use common::ui::{UI, Status};

const SCAFFOLDING_GO_IDENT: &'static str = "core/scaffolding-go";
const SCAFFOLDING_GRADLE_IDENT: &'static str = "core/scaffolding-gradle";
const SCAFFOLDING_NODE_IDENT: &'static str = "core/scaffolding-node";
const SCAFFOLDING_RUBY_IDENT: &'static str = "core/scaffolding-ruby";

// Check to see if the --scaffolding passed matches available core scaffolding
// If not check if we've been given a pkg ident for a custom scaffolding
pub fn scaffold_check(ui: &mut UI, maybe_scaffold: Option<&str>) -> Result<Option<PackageIdent>> {
    match maybe_scaffold {
        Some(scaffold) => {
            init();
            match scaffold.to_lowercase().as_ref() {
                SCAFFOLDING_GO_IDENT |
                "go" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_GO_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Go Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                SCAFFOLDING_GRADLE_IDENT |
                "gradle" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_GRADLE_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Gradle Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                SCAFFOLDING_NODE_IDENT |
                "node" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_NODE_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Node Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                SCAFFOLDING_RUBY_IDENT |
                "ruby" => {
                    let ident = PackageIdent::from_str(SCAFFOLDING_RUBY_IDENT).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("Ruby Scaffolding '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
                _ => {
                    let ident = PackageIdent::from_str(scaffold).unwrap();
                    ui.status(
                        Status::Using,
                        &format!("custom Scaffolding: '{}'", ident),
                    )?;
                    ui.para("")?;
                    Ok(Some(ident))
                }
            }
        }
        // If nothing was passed try to autodiscover the codebase
        // I'm not saying it's magic. But, MAGIC.
        None => autodiscover_scaffolding(ui),
    }
}
fn autodiscover_scaffolding(ui: &mut UI) -> Result<Option<PackageIdent>> {
    // Determine if the current dir has an app that can use
    // one of our scaffoldings and use it by default
    ui.begin("Attempting autodiscovery ")?;
    ui.para(
        "No scaffolding type was provided. Let's see if we can figure out \
        what kind of application you're planning to package.",
    )?;
    let current_path = Path::new(".");
    if is_project_go(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_GO_IDENT).unwrap();
        ui.begin("We've detected a Go codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else if is_project_gradle(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_GRADLE_IDENT).unwrap();
        ui.begin("We've detected a Gradle codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else if is_project_node(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_NODE_IDENT).unwrap();
        ui.begin("We've detected a Node.js codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else if is_project_ruby(&current_path) {
        let ident = PackageIdent::from_str(SCAFFOLDING_RUBY_IDENT).unwrap();
        ui.begin("We've detected a Ruby codebase")?;
        ui.status(
            Status::Using,
            &format!("Scaffolding package: '{}'", ident),
        )?;
        ui.para("")?;
        Ok(Some(ident))
    } else {
        ui.warn(
            "Unable to determine the type of app in your current directory",
        )?;
        ui.para(
            "For now, we'll generate a plan with all of the available plan variables and build \
            phase callbacks. For more documentation on plan options try passing --withdocs \
            or visit https://www.habitat.sh/docs/reference/plan-syntax/",
        )?;
        Ok(None)
    }
}

fn is_project_go<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("main.go").is_file() ||
        path.as_ref().join("Godeps/Godeps.json").is_file() ||
        path.as_ref().join("vendor/vendor.json").is_file() ||
        path.as_ref().join("glide.yaml").is_file() ||
        project_uses_gb(path.as_ref()).expect("Result<bool> not returned from .go file check")
    {
        return true;
    }
    return false;
}

fn is_project_gradle<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("build.gradle").is_file() ||
        path.as_ref().join("settings.gradle").is_file()
    {
        return true;
    }
    return false;
}

fn is_project_node<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("package.json").is_file() {
        return true;
    }
    return false;
}

fn is_project_ruby<T>(path: T) -> bool
where
    T: AsRef<Path>,
{
    if path.as_ref().join("Gemfile").is_file() {
        return true;
    }
    return false;
}

fn project_uses_gb(dir: &Path) -> io::Result<bool> {
    if dir.is_dir() {
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                project_uses_gb(&path)?;
            } else if path.is_file() {
                if let Some(ext) = path.extension() {
                    if ext == "go" {
                        return Ok(true);
                    }
                }
            } else {
                return Ok(false);
            }
        }
    }
    return Ok(false);
}
<|endoftext|>