<commit_before>use dbus::Connection as DBusConnection;
use dbus::{BusType, Path, ConnPath, Message};
use dbus::arg::{Variant, Iter, Array, Get, RefArg};
use dbus::stdintf::OrgFreedesktopDBusProperties;
use dbus::Error;

pub const DEFAULT_TIMEOUT: u64 = 10;
pub const RETRIES_ALLOWED: usize = 10;

pub struct DBusApi {
    connection: DBusConnection,
    method_timeout: u64,
    base: &'static str,
    method_retry_error_names: Vec<&'static str>,
}

impl DBusApi {
    pub fn new(base: &'static str, method_retry_error_names: Vec<&'static str>) -> Self {
        let connection = DBusConnection::get_private(BusType::System).unwrap();

        DBusApi {
            connection: connection,
            method_timeout: DEFAULT_TIMEOUT,
            base: base,
            method_retry_error_names: method_retry_error_names,
        }
    }

    pub fn method_timeout(&self) -> u64 {
        self.method_timeout
    }

    pub fn set_method_timeout(&mut self, timeout: u64) {
        self.method_timeout = timeout;
    }

    pub fn call(&self, path: &str, interface: &str, method: &str) -> Result<Message, String> {
        self.call_with_args(path, interface, method, &[])
    }

    pub fn call_with_args(&self,
                          path: &str,
                          interface: &str,
                          method: &str,
                          args: &[&RefArg])
                          -> Result<Message, String> {
        self.call_with_args_retry(path, interface, method, args)
            .map_err(|error| {
                         format!("D-Bus '{}'::'{}' method call failed on '{}': {}",
                                 interface,
                                 method,
                                 path,
                                 error)
                     })
    }

    fn call_with_args_retry(&self,
                            path: &str,
                            interface: &str,
                            method: &str,
                            args: &[&RefArg])
                            -> Result<Message, String> {
        let mut retries = 0;

        loop {
            if let Ok(result) = self.create_and_send_message(path, interface, method, args) {
                return result;
            }

            retries += 1;

            if retries == RETRIES_ALLOWED {
                return Err(format!("method failed after {} retries", RETRIES_ALLOWED));
            }

            ::std::thread::sleep(::std::time::Duration::from_secs(1));
        }
    }

    fn create_and_send_message(&self,
                               path: &str,
                               interface: &str,
                               method: &str,
                               args: &[&RefArg])
                               -> Result<Result<Message, String>, String> {
        match Message::new_method_call(self.base, path, interface, method) {
            Ok(mut message) => {
                if args.len() > 0 {
                    message = message.append_ref(args);
                }

                self.send_message_checked(message)
            }
            Err(details) => Ok(Err(details)),
        }
    }

    fn send_message_checked(&self, message: Message) -> Result<Result<Message, String>, String> {
        match self.connection
                  .send_with_reply_and_block(message, self.method_timeout as i32 * 1000) {
            Ok(response) => Ok(Ok(response)),
            Err(err) => {
                let message = get_error_message(&err).to_string();

                let name = err.name();
                for error_name in &self.method_retry_error_names {
                    if name == Some(error_name) {
                        return Err(message);
                    }
                }

                Ok(Err(message))
            }
        }
    }

    pub fn property<T>(&self, path: &str, interface: &str, name: &str) -> Result<T, String>
        where DBusApi: VariantTo<T>
    {
        let property_error = |details: &str| {
            Err(format!("D-Bus get '{}'::'{}' property failed on '{}': {}",
                        interface,
                        name,
                        path,
                        details))
        };

        let path = self.with_path(path);

        match path.get(interface, name) {
            Ok(variant) => {
                match DBusApi::variant_to(variant) {
                    Some(data) => Ok(data),
                    None => property_error("wrong property type"),
                }
            }
            Err(err) => {
                match err.message() {
                    Some(details) => property_error(details),
                    None => property_error("no details"),
                }
            }
        }
    }

    pub fn extract<'a, T>(&self, response: &'a Message) -> Result<T, String>
        where T: Get<'a>
    {
        response
            .get1()
            .ok_or("D-Bus wrong response type".to_string())
    }

    pub fn extract_two<'a, T1, T2>(&self, response: &'a Message) -> Result<(T1, T2), String>
        where T1: Get<'a>,
              T2: Get<'a>
    {
        let (first, second) = response.get2();

        if let Some(first) = first {
            if let Some(second) = second {
                return Ok((first, second));
            }
        }

        Err("D-Bus wrong response type".to_string())
    }

    fn with_path<'a, P: Into<Path<'a>>>(&'a self, path: P) -> ConnPath<'a, &'a DBusConnection> {
        self.connection
            .with_path(self.base, path, self.method_timeout as i32 * 1000)
    }
}

pub trait VariantTo<T> {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<T>;
}

impl VariantTo<String> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<String> {
        variant_to_string(value)
    }
}

impl VariantTo<i64> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<i64> {
        variant_to_i64(value)
    }
}

impl VariantTo<u32> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<u32> {
        variant_to_u32(value)
    }
}

impl VariantTo<bool> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<bool> {
        variant_to_bool(value)
    }
}

impl VariantTo<Vec<String>> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<Vec<String>> {
        variant_to_string_vec(value)
    }
}

impl VariantTo<Vec<u8>> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<Vec<u8>> {
        variant_to_u8_vec(value)
    }
}

fn variant_to_string_vec(value: Variant<Box<RefArg>>) -> Option<Vec<String>> {
    let mut result = Vec::new();

    if let Some(list) = value.0.as_iter() {
        for element in list {
            if let Some(string) = element.as_str() {
                result.push(string.to_string());
            } else {
                return None;
            }
        }

        Some(result)
    } else {
        None
    }
}

fn variant_to_u8_vec(value: Variant<Box<RefArg>>) -> Option<Vec<u8>> {
    let mut result = Vec::new();

    if let Some(list) = value.0.as_iter() {
        for element in list {
            if let Some(value) = element.as_i64() {
                result.push(value as u8);
            } else {
                return None;
            }
        }

        Some(result)
    } else {
        None
    }
}

fn variant_to_string(value: Variant<Box<RefArg>>) -> Option<String> {
    value.0.as_str().and_then(|v| Some(v.to_string()))
}

fn variant_to_i64(value: Variant<Box<RefArg>>) -> Option<i64> {
    value.0.as_i64()
}

fn variant_to_u32(value: Variant<Box<RefArg>>) -> Option<u32> {
    value.0.as_i64().and_then(|v| Some(v as u32))
}

fn variant_to_bool(value: Variant<Box<RefArg>>) -> Option<bool> {
    value.0.as_i64().and_then(|v| Some(v == 0))
}

pub fn extract<'a, T>(var: &'a Variant<Iter>) -> Result<T, String>
    where T: Get<'a>
{
    var.0
        .clone()
        .get::<T>()
        .ok_or(format!("D-Bus variant type does not match: {:?}", var))
}

pub fn utf8_vec_u8_to_string(var: Vec<u8>) -> Result<String, String> {
    String::from_utf8(var).or(Err(format!("D-Bus variant not a UTF-8 string")))
}

pub fn utf8_variant_to_string(var: &Variant<Iter>) -> Result<String, String> {
    let array_option = &var.0.clone().get::<Array<u8, _>>();

    if let Some(array) = *array_option {
        utf8_vec_u8_to_string(array.collect())
    } else {
        Err(format!("D-Bus variant not an array: {:?}", var))
    }
}

pub fn string_to_utf8_vec_u8(var: &String) -> Vec<u8> {
    var.as_bytes().to_vec()
}

pub fn path_to_string(path: &Path) -> Result<String, String> {
    if let Ok(slice) = path.as_cstr().to_str() {
        Ok(slice.to_string())
    } else {
        Err(format!("Path not a UTF-8 string: {:?}", path))
    }
}

fn get_error_message(err: &Error) -> &str {
    match err.message() {
        Some(details) => details,
        None => "Undefined error message",
    }
}
<commit_msg>Simplifying the result of DBusApi::create_and_send_message<commit_after>use dbus::Connection as DBusConnection;
use dbus::{BusType, Path, ConnPath, Message};
use dbus::arg::{Variant, Iter, Array, Get, RefArg};
use dbus::stdintf::OrgFreedesktopDBusProperties;
use dbus::Error;

pub const DEFAULT_TIMEOUT: u64 = 10;
pub const RETRIES_ALLOWED: usize = 10;

pub struct DBusApi {
    connection: DBusConnection,
    method_timeout: u64,
    base: &'static str,
    method_retry_error_names: Vec<&'static str>,
}

impl DBusApi {
    pub fn new(base: &'static str, method_retry_error_names: Vec<&'static str>) -> Self {
        let connection = DBusConnection::get_private(BusType::System).unwrap();

        DBusApi {
            connection: connection,
            method_timeout: DEFAULT_TIMEOUT,
            base: base,
            method_retry_error_names: method_retry_error_names,
        }
    }

    pub fn method_timeout(&self) -> u64 {
        self.method_timeout
    }

    pub fn set_method_timeout(&mut self, timeout: u64) {
        self.method_timeout = timeout;
    }

    pub fn call(&self, path: &str, interface: &str, method: &str) -> Result<Message, String> {
        self.call_with_args(path, interface, method, &[])
    }

    pub fn call_with_args(&self,
                          path: &str,
                          interface: &str,
                          method: &str,
                          args: &[&RefArg])
                          -> Result<Message, String> {
        self.call_with_args_retry(path, interface, method, args)
            .map_err(|error| {
                         format!("D-Bus '{}'::'{}' method call failed on '{}': {}",
                                 interface,
                                 method,
                                 path,
                                 error)
                     })
    }

    fn call_with_args_retry(&self,
                            path: &str,
                            interface: &str,
                            method: &str,
                            args: &[&RefArg])
                            -> Result<Message, String> {
        let mut retries = 0;

        loop {
            if let Some(result) = self.create_and_send_message(path, interface, method, args) {
                return result;
            }

            retries += 1;

            if retries == RETRIES_ALLOWED {
                return Err(format!("method failed after {} retries", RETRIES_ALLOWED));
            }

            ::std::thread::sleep(::std::time::Duration::from_secs(1));
        }
    }

    fn create_and_send_message(&self,
                               path: &str,
                               interface: &str,
                               method: &str,
                               args: &[&RefArg])
                               -> Option<Result<Message, String>> {
        match Message::new_method_call(self.base, path, interface, method) {
            Ok(mut message) => {
                if args.len() > 0 {
                    message = message.append_ref(args);
                }

                self.send_message_checked(message)
            }
            Err(details) => Some(Err(details)),
        }
    }

    fn send_message_checked(&self, message: Message) -> Option<Result<Message, String>> {
        match self.connection
                  .send_with_reply_and_block(message, self.method_timeout as i32 * 1000) {
            Ok(response) => Some(Ok(response)),
            Err(err) => {
                let message = get_error_message(&err).to_string();

                let name = err.name();
                for error_name in &self.method_retry_error_names {
                    if name == Some(error_name) {
                        return None;
                    }
                }

                Some(Err(message))
            }
        }
    }

    pub fn property<T>(&self, path: &str, interface: &str, name: &str) -> Result<T, String>
        where DBusApi: VariantTo<T>
    {
        let property_error = |details: &str| {
            Err(format!("D-Bus get '{}'::'{}' property failed on '{}': {}",
                        interface,
                        name,
                        path,
                        details))
        };

        let path = self.with_path(path);

        match path.get(interface, name) {
            Ok(variant) => {
                match DBusApi::variant_to(variant) {
                    Some(data) => Ok(data),
                    None => property_error("wrong property type"),
                }
            }
            Err(err) => {
                match err.message() {
                    Some(details) => property_error(details),
                    None => property_error("no details"),
                }
            }
        }
    }

    pub fn extract<'a, T>(&self, response: &'a Message) -> Result<T, String>
        where T: Get<'a>
    {
        response
            .get1()
            .ok_or("D-Bus wrong response type".to_string())
    }

    pub fn extract_two<'a, T1, T2>(&self, response: &'a Message) -> Result<(T1, T2), String>
        where T1: Get<'a>,
              T2: Get<'a>
    {
        let (first, second) = response.get2();

        if let Some(first) = first {
            if let Some(second) = second {
                return Ok((first, second));
            }
        }

        Err("D-Bus wrong response type".to_string())
    }

    fn with_path<'a, P: Into<Path<'a>>>(&'a self, path: P) -> ConnPath<'a, &'a DBusConnection> {
        self.connection
            .with_path(self.base, path, self.method_timeout as i32 * 1000)
    }
}

pub trait VariantTo<T> {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<T>;
}

impl VariantTo<String> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<String> {
        variant_to_string(value)
    }
}

impl VariantTo<i64> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<i64> {
        variant_to_i64(value)
    }
}

impl VariantTo<u32> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<u32> {
        variant_to_u32(value)
    }
}

impl VariantTo<bool> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<bool> {
        variant_to_bool(value)
    }
}

impl VariantTo<Vec<String>> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<Vec<String>> {
        variant_to_string_vec(value)
    }
}

impl VariantTo<Vec<u8>> for DBusApi {
    fn variant_to(value: Variant<Box<RefArg>>) -> Option<Vec<u8>> {
        variant_to_u8_vec(value)
    }
}

fn variant_to_string_vec(value: Variant<Box<RefArg>>) -> Option<Vec<String>> {
    let mut result = Vec::new();

    if let Some(list) = value.0.as_iter() {
        for element in list {
            if let Some(string) = element.as_str() {
                result.push(string.to_string());
            } else {
                return None;
            }
        }

        Some(result)
    } else {
        None
    }
}

fn variant_to_u8_vec(value: Variant<Box<RefArg>>) -> Option<Vec<u8>> {
    let mut result = Vec::new();

    if let Some(list) = value.0.as_iter() {
        for element in list {
            if let Some(value) = element.as_i64() {
                result.push(value as u8);
            } else {
                return None;
            }
        }

        Some(result)
    } else {
        None
    }
}

fn variant_to_string(value: Variant<Box<RefArg>>) -> Option<String> {
    value.0.as_str().and_then(|v| Some(v.to_string()))
}

fn variant_to_i64(value: Variant<Box<RefArg>>) -> Option<i64> {
    value.0.as_i64()
}

fn variant_to_u32(value: Variant<Box<RefArg>>) -> Option<u32> {
    value.0.as_i64().and_then(|v| Some(v as u32))
}

fn variant_to_bool(value: Variant<Box<RefArg>>) -> Option<bool> {
    value.0.as_i64().and_then(|v| Some(v == 0))
}

pub fn extract<'a, T>(var: &'a Variant<Iter>) -> Result<T, String>
    where T: Get<'a>
{
    var.0
        .clone()
        .get::<T>()
        .ok_or(format!("D-Bus variant type does not match: {:?}", var))
}

pub fn utf8_vec_u8_to_string(var: Vec<u8>) -> Result<String, String> {
    String::from_utf8(var).or(Err(format!("D-Bus variant not a UTF-8 string")))
}

pub fn utf8_variant_to_string(var: &Variant<Iter>) -> Result<String, String> {
    let array_option = &var.0.clone().get::<Array<u8, _>>();

    if let Some(array) = *array_option {
        utf8_vec_u8_to_string(array.collect())
    } else {
        Err(format!("D-Bus variant not an array: {:?}", var))
    }
}

pub fn string_to_utf8_vec_u8(var: &String) -> Vec<u8> {
    var.as_bytes().to_vec()
}

pub fn path_to_string(path: &Path) -> Result<String, String> {
    if let Ok(slice) = path.as_cstr().to_str() {
        Ok(slice.to_string())
    } else {
        Err(format!("Path not a UTF-8 string: {:?}", path))
    }
}

fn get_error_message(err: &Error) -> &str {
    match err.message() {
        Some(details) => details,
        None => "Undefined error message",
    }
}
<|endoftext|>


<commit_before>use syntax::util::small_vector::SmallVector;

use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<String>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    tests: Vec<Test>
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

<commit_msg>(feat) describe! parser.<commit_after>use syntax::util::small_vector::SmallVector;

use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<String>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    tests: Vec<Test>
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

fn parse_describe(mut state: DescribeState, mut parser: parse::parser::Parser) -> DescribeState {
    // First parse the name of this describe block:
    let (name, _) = parser.parse_str();
    state.name = Some(name.get().to_string());

    // Move past the opening {
    if parse::token::LBRACE != parser.bump_and_get() {
        parser.fatal("Expected { after the description of a describe! block.");
    }

    // Now parse all tests and subsections:
    while parser.token != parse::token::RBRACE {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.tests.push(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                });
            },

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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
//
//     https://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.

//! Kata OS CAmkES component helpers

#![no_std]
#![allow(non_camel_case_types)]

use allocator;
use log::trace;
use logger::KataLogger;
use sel4_sys;
use slot_allocator::KATA_CSPACE_SLOTS;

use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_GetCapReceivePath;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SetCap;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_Word;
use sel4_sys::seL4_WordBits;

pub type seL4_CPath = (seL4_CPtr, seL4_CPtr, seL4_Word);

extern "C" {
    // CAmkES components marked with
    //    attribute integer kataos = 1;
    // automatically get a self-reference to their top-level CNode and
    // the slot #'s of the first & last free slots in the CNode.
    static SELF_CNODE: seL4_CPtr;
    static SELF_CNODE_FIRST_SLOT: seL4_CPtr;
    static SELF_CNODE_LAST_SLOT: seL4_CPtr;
}

// Flag or'd into reply capability to indicate the cap should be
// deleted _after_ the reply is done. This depends on KataOS-specific
// CAmkES support enabled through build glue (cbindgen processes this
// crate to generate CamkesBindings.h which exports #define CAP_RELEASE
// that enables the necessaery #ifdef's).
pub const CAP_RELEASE: usize = 0x8000_0000;

// RAII wrapper for handling request cap cleanup.
pub struct RequestCapCleanup {}
impl Drop for RequestCapCleanup {
    fn drop(&mut self) {
        unsafe {
            seL4_SetCap(0, 0);
        }
    }
}

pub struct Camkes {
    name: &'static str,    // Component name
    recv_path: seL4_CPath, // IPCBuffer receive path
}

impl Camkes {
    pub const fn new(name: &'static str) -> Self {
        Camkes {
            name,
            recv_path: (seL4_CPtr::MAX, seL4_CPtr::MAX, seL4_Word::MAX),
        }
    }

    pub fn init_logger(self: &Camkes, level: log::LevelFilter) {
        static KATA_LOGGER: KataLogger = KataLogger;
        log::set_logger(&KATA_LOGGER).unwrap();
        log::set_max_level(level);
    }

    pub fn init_allocator(self: &Camkes, heap: &'static mut [u8]) {
        unsafe {
            allocator::ALLOCATOR.init(heap.as_mut_ptr() as usize, heap.len());
        }
        trace!("setup heap: start_addr {:p} size {}", heap.as_ptr(), heap.len());
    }

    pub fn init_slot_allocator(self: &Camkes, first_slot: seL4_CPtr, last_slot: seL4_CPtr) {
        unsafe {
            KATA_CSPACE_SLOTS.init(self.name, first_slot, last_slot - first_slot);
            trace!(
                "setup cspace slots: first slot {} free {}",
                KATA_CSPACE_SLOTS.base_slot(),
                KATA_CSPACE_SLOTS.free_slots()
            );
        }
    }

    pub fn pre_init(self: &Camkes, level: log::LevelFilter, heap: &'static mut [u8]) {
        self.init_logger(level);
        self.init_allocator(heap);
        unsafe {
            self.init_slot_allocator(SELF_CNODE_FIRST_SLOT, SELF_CNODE_LAST_SLOT);
        }
    }

    pub fn top_level_path(slot: seL4_CPtr) -> seL4_CPath {
        unsafe { (SELF_CNODE, slot, seL4_WordBits) }
    }

    // Initializes the IPCBuffer receive path with |path|.
    pub fn init_recv_path(self: &mut Camkes, path: &seL4_CPath) {
        self.recv_path = *path;
        unsafe {
            seL4_SetCapReceivePath(path.0, path.1, path.2);
        }
        trace!("{}: Cap receive path {:?}", self.name, path);
    }

    // Returns the path specified with init_recv_path.
    pub fn get_recv_path(self: &Camkes) -> seL4_CPath { self.recv_path }

    // Returns the component name.
    pub fn get_name(self: &Camkes) -> &'static str { self.name }

    // Returns the current receive path from the IPCBuffer.
    pub fn get_current_recv_path(self: &Camkes) -> seL4_CPath {
        unsafe { seL4_GetCapReceivePath() }
    }

    // Clears any capability the receive path path points to.
    pub fn clear_recv_path(self: &Camkes) {
        let path = &self.recv_path;
        // Assert since future receives are likely to fail
        unsafe { seL4_CNode_Delete(path.0, path.1, path.2 as u8) }.expect(self.name);
    }

    // Check the current receive path in the IPCBuffer against what was
    // setup with init_recv_path.
    pub fn check_recv_path(self: &Camkes) -> bool {
        self.get_current_recv_path() == self.get_recv_path()
    }

    // Like check_recv_path but asserts if there is an inconsistency.
    pub fn assert_recv_path(self: &Camkes) {
        assert!(
            self.check_recv_path(),
            "Current receive path {:?} does not match init'd path {:?}",
            self.get_current_recv_path(),
            self.recv_path
        );
    }

    // Attaches a capability to a CAmkES RPC request msg. seL4 will copy
    // the capabiltiy.
    #[must_use]
    pub fn set_request_cap(cptr: seL4_CPtr) -> RequestCapCleanup {
        unsafe {
            seL4_SetCap(0, cptr);
        }
        RequestCapCleanup {}
    }

    // Attaches a capability to a CAmkES RPC reply msg. seL4 will copy
    // the capabiltiy.
    pub fn set_reply_cap(cptr: seL4_CPtr) {
        unsafe {
            seL4_SetCap(0, cptr);
        }
    }

    // Attaches a capability to a CAmkES RPC reply msg and arranges for
    // the capability to be released after the reply completes.
    pub fn set_reply_cap_release(cptr: seL4_CPtr) {
        unsafe {
            // NB: logically this belongs in the CAmkES code where the
            // cap is deleted but that's not possible so do it here--there
            // should be no race to re-purpose the slot since everything
            // is assumed single-threaded (and CAmkES-generated code does
            // not short-circuit the cap delete).
            KATA_CSPACE_SLOTS.free(cptr, 1);
            seL4_SetCap(0, cptr | CAP_RELEASE);
        }
    }

    // Clears any capability attached to a CAmkES RPC reply msg.
    pub fn clear_reply_cap() { Camkes::set_reply_cap(0); }

    // Wrappers for sel4_sys::debug_assert macros.
    pub fn debug_assert_slot_empty(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_empty!(
            path.1,
            "{}: expected slot {:?} empty but has cap type {:?}",
            tag,
            path,
            sel4_sys::cap_identify(path.1)
        );
    }
    pub fn debug_assert_slot_cnode(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_cnode!(
            path.1,
            "{}: expected cnode in slot {:?} but found cap type {:?}",
            tag,
            path,
            sel4_sys::cap_identify(path.1)
        );
    }
    pub fn debug_assert_slot_frame(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_frame!(
            path.1,
            "{}: expected frame in slot {:?} but found cap type {:?}",
            tag,
            path,
            sel4_sys::cap_identify(path.1)
        );
    }

    // Dumps the contents of the toplevel CNode to the serial console.
    pub fn capscan() -> seL4_Result {
        // TODO(sleffler): requires CONFIG_PRINTING in the kernel
        #[cfg(feature = "CONFIG_PRINTING")]
        unsafe {
            sel4_sys::seL4_DebugDumpCNode(SELF_CNODE);
        }
        // XXX until seL4_Error is correctly returned
        Ok(())
    }
}
<commit_msg>kata-os-cmakes: add get_request_cap<commit_after>// Copyright 2022 Google LLC
//
// 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
//
//     https://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.

//! Kata OS CAmkES component helpers

#![no_std]
#![allow(non_camel_case_types)]

use allocator;
use log::trace;
use logger::KataLogger;
use sel4_sys;
use slot_allocator::KATA_CSPACE_SLOTS;

use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_GetCap;
use sel4_sys::seL4_GetCapReceivePath;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SetCap;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_Word;
use sel4_sys::seL4_WordBits;

pub type seL4_CPath = (seL4_CPtr, seL4_CPtr, seL4_Word);

extern "C" {
    // CAmkES components marked with
    //    attribute integer kataos = 1;
    // automatically get a self-reference to their top-level CNode and
    // the slot #'s of the first & last free slots in the CNode.
    static SELF_CNODE: seL4_CPtr;
    static SELF_CNODE_FIRST_SLOT: seL4_CPtr;
    static SELF_CNODE_LAST_SLOT: seL4_CPtr;
}

// Flag or'd into reply capability to indicate the cap should be
// deleted _after_ the reply is done. This depends on KataOS-specific
// CAmkES support enabled through build glue (cbindgen processes this
// crate to generate CamkesBindings.h which exports #define CAP_RELEASE
// that enables the necessaery #ifdef's).
pub const CAP_RELEASE: usize = 0x8000_0000;

// RAII wrapper for handling request cap cleanup.
pub struct RequestCapCleanup {}
impl Drop for RequestCapCleanup {
    fn drop(&mut self) {
        unsafe {
            seL4_SetCap(0, 0);
        }
    }
}

pub struct Camkes {
    name: &'static str,    // Component name
    recv_path: seL4_CPath, // IPCBuffer receive path
}

impl Camkes {
    pub const fn new(name: &'static str) -> Self {
        Camkes {
            name,
            recv_path: (seL4_CPtr::MAX, seL4_CPtr::MAX, seL4_Word::MAX),
        }
    }

    pub fn init_logger(self: &Camkes, level: log::LevelFilter) {
        static KATA_LOGGER: KataLogger = KataLogger;
        log::set_logger(&KATA_LOGGER).unwrap();
        log::set_max_level(level);
    }

    pub fn init_allocator(self: &Camkes, heap: &'static mut [u8]) {
        unsafe {
            allocator::ALLOCATOR.init(heap.as_mut_ptr() as usize, heap.len());
        }
        trace!("setup heap: start_addr {:p} size {}", heap.as_ptr(), heap.len());
    }

    pub fn init_slot_allocator(self: &Camkes, first_slot: seL4_CPtr, last_slot: seL4_CPtr) {
        unsafe {
            KATA_CSPACE_SLOTS.init(self.name, first_slot, last_slot - first_slot);
            trace!(
                "setup cspace slots: first slot {} free {}",
                KATA_CSPACE_SLOTS.base_slot(),
                KATA_CSPACE_SLOTS.free_slots()
            );
        }
    }

    pub fn pre_init(self: &Camkes, level: log::LevelFilter, heap: &'static mut [u8]) {
        self.init_logger(level);
        self.init_allocator(heap);
        unsafe {
            self.init_slot_allocator(SELF_CNODE_FIRST_SLOT, SELF_CNODE_LAST_SLOT);
        }
    }

    pub fn top_level_path(slot: seL4_CPtr) -> seL4_CPath {
        unsafe { (SELF_CNODE, slot, seL4_WordBits) }
    }

    // Initializes the IPCBuffer receive path with |path|.
    pub fn init_recv_path(self: &mut Camkes, path: &seL4_CPath) {
        self.recv_path = *path;
        unsafe {
            seL4_SetCapReceivePath(path.0, path.1, path.2);
        }
        trace!("{}: Cap receive path {:?}", self.name, path);
    }

    // Returns the path specified with init_recv_path.
    pub fn get_recv_path(self: &Camkes) -> seL4_CPath { self.recv_path }

    // Returns the component name.
    pub fn get_name(self: &Camkes) -> &'static str { self.name }

    // Returns the current receive path from the IPCBuffer.
    pub fn get_current_recv_path(self: &Camkes) -> seL4_CPath {
        unsafe { seL4_GetCapReceivePath() }
    }

    // Clears any capability the receive path path points to.
    pub fn clear_recv_path(self: &Camkes) {
        let path = &self.recv_path;
        // Assert since future receives are likely to fail
        unsafe { seL4_CNode_Delete(path.0, path.1, path.2 as u8) }.expect(self.name);
    }

    // Check the current receive path in the IPCBuffer against what was
    // setup with init_recv_path.
    pub fn check_recv_path(self: &Camkes) -> bool {
        self.get_current_recv_path() == self.get_recv_path()
    }

    // Like check_recv_path but asserts if there is an inconsistency.
    pub fn assert_recv_path(self: &Camkes) {
        assert!(
            self.check_recv_path(),
            "Current receive path {:?} does not match init'd path {:?}",
            self.get_current_recv_path(),
            self.recv_path
        );
    }

    // Attaches a capability to a CAmkES RPC request msg. seL4 will copy
    // the capabiltiy.
    #[must_use]
    pub fn set_request_cap(cptr: seL4_CPtr) -> RequestCapCleanup {
        unsafe {
            seL4_SetCap(0, cptr);
        }
        RequestCapCleanup {}
    }

    // Returns the capability attached to an seL4 IPC.
    pub fn get_request_cap() -> seL4_CPtr { unsafe { seL4_GetCap(0) } }

    // Attaches a capability to a CAmkES RPC reply msg. seL4 will copy
    // the capabiltiy.
    pub fn set_reply_cap(cptr: seL4_CPtr) {
        unsafe {
            seL4_SetCap(0, cptr);
        }
    }

    // Attaches a capability to a CAmkES RPC reply msg and arranges for
    // the capability to be released after the reply completes.
    pub fn set_reply_cap_release(cptr: seL4_CPtr) {
        unsafe {
            // NB: logically this belongs in the CAmkES code where the
            // cap is deleted but that's not possible so do it here--there
            // should be no race to re-purpose the slot since everything
            // is assumed single-threaded (and CAmkES-generated code does
            // not short-circuit the cap delete).
            KATA_CSPACE_SLOTS.free(cptr, 1);
            seL4_SetCap(0, cptr | CAP_RELEASE);
        }
    }

    // Clears any capability attached to a CAmkES RPC reply msg.
    pub fn clear_reply_cap() { Camkes::set_reply_cap(0); }

    // Wrappers for sel4_sys::debug_assert macros.
    pub fn debug_assert_slot_empty(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_empty!(
            path.1,
            "{}: expected slot {:?} empty but has cap type {:?}",
            tag,
            path,
            sel4_sys::cap_identify(path.1)
        );
    }
    pub fn debug_assert_slot_cnode(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_cnode!(
            path.1,
            "{}: expected cnode in slot {:?} but found cap type {:?}",
            tag,
            path,
            sel4_sys::cap_identify(path.1)
        );
    }
    pub fn debug_assert_slot_frame(tag: &str, path: &seL4_CPath) {
        sel4_sys::debug_assert_slot_frame!(
            path.1,
            "{}: expected frame in slot {:?} but found cap type {:?}",
            tag,
            path,
            sel4_sys::cap_identify(path.1)
        );
    }

    // Dumps the contents of the toplevel CNode to the serial console.
    pub fn capscan() -> seL4_Result {
        // TODO(sleffler): requires CONFIG_PRINTING in the kernel
        #[cfg(feature = "CONFIG_PRINTING")]
        unsafe {
            sel4_sys::seL4_DebugDumpCNode(SELF_CNODE);
        }
        // XXX until seL4_Error is correctly returned
        Ok(())
    }
}
<|endoftext|>


<commit_before>use core::convert::Infallible;

/// Enum mapping type
///
/// This trait is internally used by `#[derive(Enum)]`. `Enum<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
///
/// This trait is also implemented by `bool` and `u8`. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Enum: Sized {
    /// Length of the enum.
    const LENGTH: usize;

    /// Takes an usize, and returns an element matching `into_usize` function.
    fn from_usize(value: usize) -> Self;
    /// Returns an unique identifier for a value within range of `0..Array::LENGTH`.
    fn into_usize(self) -> usize;
}

/// Trait associating
pub trait EnumArray<V>: Enum {
    /// Representation of an enum map for type `V`.
    type Array: Array<V>;
}

/// Array for enum-map storage.
///
/// This trait is inteded for primitive array types (with fixed length).
pub unsafe trait Array<V> {
    // This is necessary duplication because the length in Enum trait can be
    // provided by user and may not be trustworthy for unsafe code.
    const LENGTH: usize;

    /// Coerces a reference to the array into a reference to a slice.
    fn slice(&self) -> &[V];

    /// Coerces a mutable reference to the array into a mutable reference to a slice.
    fn slice_mut(&mut self) -> &mut [V];
}

unsafe impl<V, const N: usize> Array<V> for [V; N] {
    const LENGTH: usize = N;
    fn slice(&self) -> &[V] {
        self
    }
    fn slice_mut(&mut self) -> &mut [V] {
        self
    }
}

impl Enum for bool {
    const LENGTH: usize = 2;

    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for bool {
    type Array = [T; Self::LENGTH];
}

impl Enum for u8 {
    const LENGTH: usize = 256;

    #[inline]
    fn from_usize(value: usize) -> Self {
        value.try_into().unwrap()
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for u8 {
    type Array = [T; Self::LENGTH];
}

impl Enum for Infallible {
    const LENGTH: usize = 0;

    #[inline]
    fn from_usize(_: usize) -> Self {
        unreachable!();
    }
    #[inline]
    fn into_usize(self) -> usize {
        match self {}
    }
}

impl<T> EnumArray<T> for Infallible {
    type Array = [T; Self::LENGTH];
}
<commit_msg>Document safety of Array trait<commit_after>use core::convert::Infallible;

/// Enum mapping type
///
/// This trait is internally used by `#[derive(Enum)]`. `Enum<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
///
/// This trait is also implemented by `bool` and `u8`. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Enum: Sized {
    /// Length of the enum.
    const LENGTH: usize;

    /// Takes an usize, and returns an element matching `into_usize` function.
    fn from_usize(value: usize) -> Self;
    /// Returns an unique identifier for a value within range of `0..Array::LENGTH`.
    fn into_usize(self) -> usize;
}

/// Trait associating
pub trait EnumArray<V>: Enum {
    /// Representation of an enum map for type `V`.
    type Array: Array<V>;
}

/// Array for enum-map storage.
///
/// This trait is inteded for primitive array types (with fixed length).
///
/// # Safety
///
/// The array length needs to match actual storage.
pub unsafe trait Array<V> {
    // This is necessary duplication because the length in Enum trait can be
    // provided by user and may not be trustworthy for unsafe code.
    const LENGTH: usize;

    /// Coerces a reference to the array into a reference to a slice.
    fn slice(&self) -> &[V];

    /// Coerces a mutable reference to the array into a mutable reference to a slice.
    fn slice_mut(&mut self) -> &mut [V];
}

unsafe impl<V, const N: usize> Array<V> for [V; N] {
    const LENGTH: usize = N;
    fn slice(&self) -> &[V] {
        self
    }
    fn slice_mut(&mut self) -> &mut [V] {
        self
    }
}

impl Enum for bool {
    const LENGTH: usize = 2;

    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for bool {
    type Array = [T; Self::LENGTH];
}

impl Enum for u8 {
    const LENGTH: usize = 256;

    #[inline]
    fn from_usize(value: usize) -> Self {
        value.try_into().unwrap()
    }
    #[inline]
    fn into_usize(self) -> usize {
        usize::from(self)
    }
}

impl<T> EnumArray<T> for u8 {
    type Array = [T; Self::LENGTH];
}

impl Enum for Infallible {
    const LENGTH: usize = 0;

    #[inline]
    fn from_usize(_: usize) -> Self {
        unreachable!();
    }
    #[inline]
    fn into_usize(self) -> usize {
        match self {}
    }
}

impl<T> EnumArray<T> for Infallible {
    type Array = [T; Self::LENGTH];
}
<|endoftext|>


<commit_before>use std::collections::hash_set::HashSet;
use std::iter::FromIterator;

use api::server_data::ServerData;
use api::result::*;
use web::data::{APIGeneSummary, TranscriptDetails, FeatureType, GeneShort, InteractionType};

use types::GeneUniquename;

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum IntRangeType {
#[serde(rename = "protein_length")]
    ProteinLength,
#[serde(rename = "tm_domain_count")]
    TMDomainCount,
#[serde(rename = "exon_count")]
    ExonCount,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum FloatRangeType {
#[serde(rename = "protein_mol_weight")]
    ProteinMolWeight,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum SingleOrMultiAllele {
#[serde(rename = "single")]
    Single,
#[serde(rename = "multi")]
    Multi,
#[serde(rename = "both")]
    Both,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum QueryExpressionFilter {
#[serde(rename = "any")]
    Any,
#[serde(rename = "null")]
    Null,
#[serde(rename = "wt-overexpressed")]
    WtOverexpressed,
}

type TermName = String;
type QueryRowsResult = Result<Vec<ResultRow>, String>;
type GeneUniquenameVecResult = Result<Vec<GeneUniquename>, String>;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum QueryNode {
#[serde(rename = "or")]
    Or(Vec<QueryNode>),
#[serde(rename = "and")]
    And(Vec<QueryNode>),
#[serde(rename = "not")]
    Not { node_a: Box<QueryNode>, node_b: Box<QueryNode> },
#[serde(rename = "term")]
    Term {
        termid: String,
        name: Option<TermName>,
        single_or_multi_allele: Option<SingleOrMultiAllele>,
        expression: Option<QueryExpressionFilter>,
    },
#[serde(rename = "subset")]
    Subset { subset_name: String },
#[serde(rename = "gene_list")]
    GeneList { genes: Vec<GeneShort> },
#[serde(rename = "int_range")]
    IntRange { range_type: IntRangeType, start: Option<u64>, end: Option<u64> },
#[serde(rename = "float_range")]
    FloatRange { range_type: FloatRangeType, start: Option<f64>, end: Option<f64> },
#[serde(rename = "genome_range_contains")]
    GenomeRangeContains { start: Option<u64>, end: Option<u64>, chromosome_name: String, },
#[serde(rename = "interactors")]
    Interactors { gene_uniquename: GeneUniquename, interaction_type: String },
}

fn exec_or(server_data: &ServerData, nodes: &Vec<QueryNode>) -> GeneUniquenameVecResult {
    if nodes.len() == 0 {
        return Err("illegal query: OR operator has no nodes".into());
    }

    let mut seen_genes = HashSet::new();
    let mut or_rows = vec![];

    for node in nodes {
        let exec_rows = node.exec(server_data)?;

        for row_gene_uniquename in &exec_rows {
            if !seen_genes.contains(row_gene_uniquename) {
                or_rows.push(row_gene_uniquename.clone());
                seen_genes.insert(row_gene_uniquename.clone());
            }
        }
    }

    Ok(or_rows)
}

fn exec_and(server_data: &ServerData, nodes: &Vec<QueryNode>) -> GeneUniquenameVecResult {
    if nodes.len() == 0 {
        return Err("illegal query: AND operator has no nodes".into());
    }

    let first_node_genes = nodes[0].exec(server_data)?;

    let current_genes = first_node_genes;

    let mut current_gene_set = HashSet::from_iter(current_genes);

    for node in nodes[1..].iter() {
        let node_result_rows = node.exec(server_data)?;
        let node_genes = node_result_rows.into_iter().collect::<HashSet<_>>();

        current_gene_set = current_gene_set.intersection(&node_genes).cloned().collect();
    }

    Ok(current_gene_set.into_iter().collect())
}

fn exec_not(server_data: &ServerData, node_a: &QueryNode, node_b: &QueryNode)
             -> GeneUniquenameVecResult
{
    let node_b_result = node_b.exec(server_data)?;

    let node_b_gene_set: HashSet<GeneUniquename> =
        HashSet::from_iter(node_b_result.into_iter());

    let node_a_result = node_a.exec(server_data)?;

    let mut not_rows = vec![];

    for row_gene_uniquename in &node_a_result {
        if !node_b_gene_set.contains(row_gene_uniquename) {
            not_rows.push(row_gene_uniquename.clone());
        }
    }

    Ok(not_rows)
}

fn exec_termid(server_data: &ServerData, term_id: &str,
               maybe_single_or_multi_allele: &Option<SingleOrMultiAllele>,
               expression: &Option<QueryExpressionFilter>)  -> GeneUniquenameVecResult {
    if let Some(ref single_or_multi_allele) = *maybe_single_or_multi_allele {
        let genes = server_data.genes_of_genotypes(term_id, single_or_multi_allele,
                                                   expression);
        Ok(genes)
    } else {
        Ok(server_data.genes_of_termid(term_id))
    }
}

fn exec_subset(server_data: &ServerData, subset_name: &str)  -> GeneUniquenameVecResult {
    Ok(server_data.genes_of_subset(subset_name))
}

fn exec_gene_list(genes: &Vec<GeneShort>)
                  -> GeneUniquenameVecResult
{
    let mut ret = vec![];

    for gene in genes {
        ret.push(gene.uniquename.clone());
    }

    Ok(ret)
}

fn exec_genome_range_overlaps(server_data: &ServerData, start: Option<u64>, end: Option<u64>,
                              chromosome_name: &str) -> GeneUniquenameVecResult {
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if let Some(ref location) = gene.location {
                (end.is_none() || location.start_pos as u64 <= end.unwrap()) &&
                    (start.is_none() || location.end_pos as u64 >= start.unwrap()) &&
                    location.chromosome.name == chromosome_name
            } else {
                false
            }
        });
    Ok(gene_uniquenames)
}

fn exec_protein_length_range(server_data: &ServerData,
                             range_start: Option<u64>, range_end: Option<u64>)
                              -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    (range_start.is_none() || protein.sequence.len() as u64 >= range_start.unwrap()) &&
                    (range_end.is_none() || protein.sequence.len() as u64 <= range_end.unwrap())
                } else {
                    false
                }
            } else {
                false
            }
        });
    Ok(gene_uniquenames)
}

fn exec_tm_domain_count_range(server_data: &ServerData,
                              range_start: Option<u64>, range_end: Option<u64>)
                               -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            (range_start.is_none() || gene.tm_domain_count as u64 >= range_start.unwrap()) &&
            (range_end.is_none() || gene.tm_domain_count as u64 <= range_end.unwrap())
        });
    Ok(gene_uniquenames)
}

fn exec_exon_count_range(server_data: &ServerData,
                         range_start: Option<u64>, range_end: Option<u64>)
                         -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            (range_start.is_none() || gene.exon_count as u64 >= range_start.unwrap()) &&
            (range_end.is_none() || gene.exon_count as u64 <= range_end.unwrap())
        });
    Ok(gene_uniquenames)
}

fn exec_int_range(server_data: &ServerData, range_type: &IntRangeType,
                  start: Option<u64>, end: Option<u64>) -> GeneUniquenameVecResult {
    match *range_type {
        IntRangeType::ProteinLength => exec_protein_length_range(server_data, start, end),
        IntRangeType::TMDomainCount => exec_tm_domain_count_range(server_data, start, end),
        IntRangeType::ExonCount => exec_exon_count_range(server_data, start, end),
    }
}

fn exec_mol_weight_range(server_data: &ServerData, range_start: Option<f64>, range_end: Option<f64>)
                         -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    (range_start.is_none() ||
                        protein.molecular_weight as f64 >= range_start.unwrap()) &&
                    (range_end.is_none() ||
                        protein.molecular_weight as f64 <= range_end.unwrap())
                } else {
                    false
                }
            } else {
                false
            }
        });
    Ok(gene_uniquenames)
}

fn exec_float_range(server_data: &ServerData, range_type: &FloatRangeType,
                    start: Option<f64>, end: Option<f64>) -> GeneUniquenameVecResult {
    match *range_type {
        FloatRangeType::ProteinMolWeight => exec_mol_weight_range(server_data, start, end)
    }
}

fn exec_interactors_of_gene(server_data: &ServerData, gene_uniquename: &GeneUniquename,
                            interaction_type: InteractionType) -> GeneUniquenameVecResult {
    Ok(server_data.interactors_of_genes(gene_uniquename, interaction_type))
}

impl QueryNode {
    pub fn exec(&self, server_data: &ServerData) -> GeneUniquenameVecResult {
        use self::QueryNode::*;
        match *self {
            Or(ref nodes) => exec_or(server_data, nodes),
            And(ref nodes) => exec_and(server_data, nodes),
            Not { ref node_a, ref node_b } => exec_not(server_data, node_a, node_b),
            Term {
                ref termid,
                name: _,
                ref single_or_multi_allele,
                ref expression,
            } => exec_termid(server_data, termid, single_or_multi_allele, expression),
            Subset { ref subset_name } => exec_subset(server_data, subset_name),
            GeneList { ref genes } => exec_gene_list(genes),
            GenomeRangeContains { start, end, ref chromosome_name } =>
                exec_genome_range_overlaps(server_data, start, end, chromosome_name),
            Interactors { ref gene_uniquename, ref interaction_type } => {
                match &interaction_type as &str {
                    "physical" =>
                        exec_interactors_of_gene(server_data, gene_uniquename,
                                                 InteractionType::Physical),
                    "genetic" =>
                        exec_interactors_of_gene(server_data, gene_uniquename,
                                                 InteractionType::Genetic),
                    _ => Err(format!("No such interaction type: {}",
                                    interaction_type))
                }
            },
            IntRange { ref range_type, start, end } =>
                exec_int_range(server_data, range_type, start, end),
            FloatRange { ref range_type, start, end } =>
                exec_float_range(server_data, range_type, start, end),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NucleotideDownloadOptions {
    include_introns: bool,
    include_5_prime_utr: bool,
    include_3_prime_utr: bool,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SeqType {
#[serde(rename = "protein")]
    Protein,
#[serde(rename = "nucleotide")]
    Nucleotide(NucleotideDownloadOptions),
#[serde(rename = "none")]
    None,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct QueryOutputOptions {
    pub sequence: SeqType,
    pub field_names: Vec<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Query {
    output_options: QueryOutputOptions,
    constraints: QueryNode,
}

impl Query {
    pub fn new(constraints: QueryNode, output_options: QueryOutputOptions) -> Query {
        Query {
            output_options: output_options,
            constraints: constraints
        }
    }

    fn make_nucleotide_sequence(&self, transcript: &TranscriptDetails,
                                options: &NucleotideDownloadOptions) -> String {
        let mut seq = String::from("");

        for part in &transcript.parts {
            if part.feature_type == FeatureType::Exon ||
                options.include_introns && part.feature_type == FeatureType::CdsIntron ||
                options.include_5_prime_utr &&
                (part.feature_type == FeatureType::FivePrimeUtr ||
                 options.include_introns && part.feature_type == FeatureType::FivePrimeUtrIntron) ||
                options.include_3_prime_utr &&
                (part.feature_type == FeatureType::ThreePrimeUtr ||
                 options.include_introns && part.feature_type == FeatureType::ThreePrimeUtrIntron) {
                    seq += &part.residues;
                }
        }

        seq
    }

    fn make_sequence(&self, server_data: &ServerData,
                     gene_uniquename: &str) -> Option<String> {
        let maybe_gene_summary = server_data.get_gene_summary(gene_uniquename);

        if let Some(gene_summary) = maybe_gene_summary {
            let maybe_transcript = gene_summary.transcripts.get(0);
            if let Some(transcript) = maybe_transcript {
                match self.output_options.sequence {
                    SeqType::Protein =>
                        if let Some(ref protein) = transcript.protein {
                            return Some(protein.sequence.clone());
                        }
                    SeqType::Nucleotide(ref options) => {
                        return Some(self.make_nucleotide_sequence(transcript, options))
                    }
                    SeqType::None => (),
                }
            }
        }

        None
    }

    fn make_result_rows(&self, server_data: &ServerData,
                        genes: Vec<String>) -> QueryRowsResult {
        Ok(genes.into_iter()
           .map(|gene_uniquename| {
               let sequence = self.make_sequence(server_data, &gene_uniquename);
               ResultRow {
                   sequence: sequence,
                   gene_uniquename: gene_uniquename,
               }
           }).collect::<Vec<_>>())
    }

    pub fn exec(&self, server_data: &ServerData) -> QueryRowsResult {
        let genes_result = self.constraints.exec(server_data);

        match genes_result {
            Ok(genes) => self.make_result_rows(server_data, genes),
            Err(err) => Err(err)
        }
    }
}
<commit_msg>Rename GenomeRangeContains to something shorter<commit_after>use std::collections::hash_set::HashSet;
use std::iter::FromIterator;

use api::server_data::ServerData;
use api::result::*;
use web::data::{APIGeneSummary, TranscriptDetails, FeatureType, GeneShort, InteractionType};

use types::GeneUniquename;

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum IntRangeType {
#[serde(rename = "protein_length")]
    ProteinLength,
#[serde(rename = "tm_domain_count")]
    TMDomainCount,
#[serde(rename = "exon_count")]
    ExonCount,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum FloatRangeType {
#[serde(rename = "protein_mol_weight")]
    ProteinMolWeight,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum SingleOrMultiAllele {
#[serde(rename = "single")]
    Single,
#[serde(rename = "multi")]
    Multi,
#[serde(rename = "both")]
    Both,
}

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
pub enum QueryExpressionFilter {
#[serde(rename = "any")]
    Any,
#[serde(rename = "null")]
    Null,
#[serde(rename = "wt-overexpressed")]
    WtOverexpressed,
}

type TermName = String;
type QueryRowsResult = Result<Vec<ResultRow>, String>;
type GeneUniquenameVecResult = Result<Vec<GeneUniquename>, String>;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum QueryNode {
#[serde(rename = "or")]
    Or(Vec<QueryNode>),
#[serde(rename = "and")]
    And(Vec<QueryNode>),
#[serde(rename = "not")]
    Not { node_a: Box<QueryNode>, node_b: Box<QueryNode> },
#[serde(rename = "term")]
    Term {
        termid: String,
        name: Option<TermName>,
        single_or_multi_allele: Option<SingleOrMultiAllele>,
        expression: Option<QueryExpressionFilter>,
    },
#[serde(rename = "subset")]
    Subset { subset_name: String },
#[serde(rename = "gene_list")]
    GeneList { genes: Vec<GeneShort> },
#[serde(rename = "int_range")]
    IntRange { range_type: IntRangeType, start: Option<u64>, end: Option<u64> },
#[serde(rename = "float_range")]
    FloatRange { range_type: FloatRangeType, start: Option<f64>, end: Option<f64> },
#[serde(rename = "genome_range")]
    GenomeRange { start: Option<u64>, end: Option<u64>, chromosome_name: String, },
#[serde(rename = "interactors")]
    Interactors { gene_uniquename: GeneUniquename, interaction_type: String },
}

fn exec_or(server_data: &ServerData, nodes: &Vec<QueryNode>) -> GeneUniquenameVecResult {
    if nodes.len() == 0 {
        return Err("illegal query: OR operator has no nodes".into());
    }

    let mut seen_genes = HashSet::new();
    let mut or_rows = vec![];

    for node in nodes {
        let exec_rows = node.exec(server_data)?;

        for row_gene_uniquename in &exec_rows {
            if !seen_genes.contains(row_gene_uniquename) {
                or_rows.push(row_gene_uniquename.clone());
                seen_genes.insert(row_gene_uniquename.clone());
            }
        }
    }

    Ok(or_rows)
}

fn exec_and(server_data: &ServerData, nodes: &Vec<QueryNode>) -> GeneUniquenameVecResult {
    if nodes.len() == 0 {
        return Err("illegal query: AND operator has no nodes".into());
    }

    let first_node_genes = nodes[0].exec(server_data)?;

    let current_genes = first_node_genes;

    let mut current_gene_set = HashSet::from_iter(current_genes);

    for node in nodes[1..].iter() {
        let node_result_rows = node.exec(server_data)?;
        let node_genes = node_result_rows.into_iter().collect::<HashSet<_>>();

        current_gene_set = current_gene_set.intersection(&node_genes).cloned().collect();
    }

    Ok(current_gene_set.into_iter().collect())
}

fn exec_not(server_data: &ServerData, node_a: &QueryNode, node_b: &QueryNode)
             -> GeneUniquenameVecResult
{
    let node_b_result = node_b.exec(server_data)?;

    let node_b_gene_set: HashSet<GeneUniquename> =
        HashSet::from_iter(node_b_result.into_iter());

    let node_a_result = node_a.exec(server_data)?;

    let mut not_rows = vec![];

    for row_gene_uniquename in &node_a_result {
        if !node_b_gene_set.contains(row_gene_uniquename) {
            not_rows.push(row_gene_uniquename.clone());
        }
    }

    Ok(not_rows)
}

fn exec_termid(server_data: &ServerData, term_id: &str,
               maybe_single_or_multi_allele: &Option<SingleOrMultiAllele>,
               expression: &Option<QueryExpressionFilter>)  -> GeneUniquenameVecResult {
    if let Some(ref single_or_multi_allele) = *maybe_single_or_multi_allele {
        let genes = server_data.genes_of_genotypes(term_id, single_or_multi_allele,
                                                   expression);
        Ok(genes)
    } else {
        Ok(server_data.genes_of_termid(term_id))
    }
}

fn exec_subset(server_data: &ServerData, subset_name: &str)  -> GeneUniquenameVecResult {
    Ok(server_data.genes_of_subset(subset_name))
}

fn exec_gene_list(genes: &Vec<GeneShort>)
                  -> GeneUniquenameVecResult
{
    let mut ret = vec![];

    for gene in genes {
        ret.push(gene.uniquename.clone());
    }

    Ok(ret)
}

fn exec_genome_range_overlaps(server_data: &ServerData, start: Option<u64>, end: Option<u64>,
                              chromosome_name: &str) -> GeneUniquenameVecResult {
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if let Some(ref location) = gene.location {
                (end.is_none() || location.start_pos as u64 <= end.unwrap()) &&
                    (start.is_none() || location.end_pos as u64 >= start.unwrap()) &&
                    location.chromosome.name == chromosome_name
            } else {
                false
            }
        });
    Ok(gene_uniquenames)
}

fn exec_protein_length_range(server_data: &ServerData,
                             range_start: Option<u64>, range_end: Option<u64>)
                              -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    (range_start.is_none() || protein.sequence.len() as u64 >= range_start.unwrap()) &&
                    (range_end.is_none() || protein.sequence.len() as u64 <= range_end.unwrap())
                } else {
                    false
                }
            } else {
                false
            }
        });
    Ok(gene_uniquenames)
}

fn exec_tm_domain_count_range(server_data: &ServerData,
                              range_start: Option<u64>, range_end: Option<u64>)
                               -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            (range_start.is_none() || gene.tm_domain_count as u64 >= range_start.unwrap()) &&
            (range_end.is_none() || gene.tm_domain_count as u64 <= range_end.unwrap())
        });
    Ok(gene_uniquenames)
}

fn exec_exon_count_range(server_data: &ServerData,
                         range_start: Option<u64>, range_end: Option<u64>)
                         -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            (range_start.is_none() || gene.exon_count as u64 >= range_start.unwrap()) &&
            (range_end.is_none() || gene.exon_count as u64 <= range_end.unwrap())
        });
    Ok(gene_uniquenames)
}

fn exec_int_range(server_data: &ServerData, range_type: &IntRangeType,
                  start: Option<u64>, end: Option<u64>) -> GeneUniquenameVecResult {
    match *range_type {
        IntRangeType::ProteinLength => exec_protein_length_range(server_data, start, end),
        IntRangeType::TMDomainCount => exec_tm_domain_count_range(server_data, start, end),
        IntRangeType::ExonCount => exec_exon_count_range(server_data, start, end),
    }
}

fn exec_mol_weight_range(server_data: &ServerData, range_start: Option<f64>, range_end: Option<f64>)
                         -> GeneUniquenameVecResult
{
    let gene_uniquenames =
        server_data.filter_genes(&|gene: &APIGeneSummary| {
            if gene.transcripts.len() > 0 {
                if let Some(ref protein) = gene.transcripts[0].protein {
                    (range_start.is_none() ||
                        protein.molecular_weight as f64 >= range_start.unwrap()) &&
                    (range_end.is_none() ||
                        protein.molecular_weight as f64 <= range_end.unwrap())
                } else {
                    false
                }
            } else {
                false
            }
        });
    Ok(gene_uniquenames)
}

fn exec_float_range(server_data: &ServerData, range_type: &FloatRangeType,
                    start: Option<f64>, end: Option<f64>) -> GeneUniquenameVecResult {
    match *range_type {
        FloatRangeType::ProteinMolWeight => exec_mol_weight_range(server_data, start, end)
    }
}

fn exec_interactors_of_gene(server_data: &ServerData, gene_uniquename: &GeneUniquename,
                            interaction_type: InteractionType) -> GeneUniquenameVecResult {
    Ok(server_data.interactors_of_genes(gene_uniquename, interaction_type))
}

impl QueryNode {
    pub fn exec(&self, server_data: &ServerData) -> GeneUniquenameVecResult {
        use self::QueryNode::*;
        match *self {
            Or(ref nodes) => exec_or(server_data, nodes),
            And(ref nodes) => exec_and(server_data, nodes),
            Not { ref node_a, ref node_b } => exec_not(server_data, node_a, node_b),
            Term {
                ref termid,
                name: _,
                ref single_or_multi_allele,
                ref expression,
            } => exec_termid(server_data, termid, single_or_multi_allele, expression),
            Subset { ref subset_name } => exec_subset(server_data, subset_name),
            GeneList { ref genes } => exec_gene_list(genes),
            GenomeRange { start, end, ref chromosome_name } =>
                exec_genome_range_overlaps(server_data, start, end, chromosome_name),
            Interactors { ref gene_uniquename, ref interaction_type } => {
                match &interaction_type as &str {
                    "physical" =>
                        exec_interactors_of_gene(server_data, gene_uniquename,
                                                 InteractionType::Physical),
                    "genetic" =>
                        exec_interactors_of_gene(server_data, gene_uniquename,
                                                 InteractionType::Genetic),
                    _ => Err(format!("No such interaction type: {}",
                                    interaction_type))
                }
            },
            IntRange { ref range_type, start, end } =>
                exec_int_range(server_data, range_type, start, end),
            FloatRange { ref range_type, start, end } =>
                exec_float_range(server_data, range_type, start, end),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NucleotideDownloadOptions {
    include_introns: bool,
    include_5_prime_utr: bool,
    include_3_prime_utr: bool,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SeqType {
#[serde(rename = "protein")]
    Protein,
#[serde(rename = "nucleotide")]
    Nucleotide(NucleotideDownloadOptions),
#[serde(rename = "none")]
    None,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct QueryOutputOptions {
    pub sequence: SeqType,
    pub field_names: Vec<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Query {
    output_options: QueryOutputOptions,
    constraints: QueryNode,
}

impl Query {
    pub fn new(constraints: QueryNode, output_options: QueryOutputOptions) -> Query {
        Query {
            output_options: output_options,
            constraints: constraints
        }
    }

    fn make_nucleotide_sequence(&self, transcript: &TranscriptDetails,
                                options: &NucleotideDownloadOptions) -> String {
        let mut seq = String::from("");

        for part in &transcript.parts {
            if part.feature_type == FeatureType::Exon ||
                options.include_introns && part.feature_type == FeatureType::CdsIntron ||
                options.include_5_prime_utr &&
                (part.feature_type == FeatureType::FivePrimeUtr ||
                 options.include_introns && part.feature_type == FeatureType::FivePrimeUtrIntron) ||
                options.include_3_prime_utr &&
                (part.feature_type == FeatureType::ThreePrimeUtr ||
                 options.include_introns && part.feature_type == FeatureType::ThreePrimeUtrIntron) {
                    seq += &part.residues;
                }
        }

        seq
    }

    fn make_sequence(&self, server_data: &ServerData,
                     gene_uniquename: &str) -> Option<String> {
        let maybe_gene_summary = server_data.get_gene_summary(gene_uniquename);

        if let Some(gene_summary) = maybe_gene_summary {
            let maybe_transcript = gene_summary.transcripts.get(0);
            if let Some(transcript) = maybe_transcript {
                match self.output_options.sequence {
                    SeqType::Protein =>
                        if let Some(ref protein) = transcript.protein {
                            return Some(protein.sequence.clone());
                        }
                    SeqType::Nucleotide(ref options) => {
                        return Some(self.make_nucleotide_sequence(transcript, options))
                    }
                    SeqType::None => (),
                }
            }
        }

        None
    }

    fn make_result_rows(&self, server_data: &ServerData,
                        genes: Vec<String>) -> QueryRowsResult {
        Ok(genes.into_iter()
           .map(|gene_uniquename| {
               let sequence = self.make_sequence(server_data, &gene_uniquename);
               ResultRow {
                   sequence: sequence,
                   gene_uniquename: gene_uniquename,
               }
           }).collect::<Vec<_>>())
    }

    pub fn exec(&self, server_data: &ServerData) -> QueryRowsResult {
        let genes_result = self.constraints.exec(server_data);

        match genes_result {
            Ok(genes) => self.make_result_rows(server_data, genes),
            Err(err) => Err(err)
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLHRElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLHRElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLHRElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLHRElement {
    pub htmlelement: HTMLElement,
}

impl HTMLHRElementDerived for EventTarget {
    fn is_htmlhrelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLHRElementTypeId))
    }
}

impl HTMLHRElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLHRElement {
        HTMLHRElement {
            htmlelement: HTMLElement::new_inherited(HTMLHRElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLHRElement> {
        let element = HTMLHRElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLHRElementBinding::Wrap)
    }
}

pub trait HTMLHRElementMethods {
    fn Align(&self) -> DOMString;
    fn SetAlign(&mut self, _align: DOMString) -> ErrorResult;
    fn Color(&self) -> DOMString;
    fn SetColor(&mut self, _color: DOMString) -> ErrorResult;
    fn NoShade(&self) -> bool;
    fn SetNoShade(&self, _no_shade: bool) -> ErrorResult;
    fn Size(&self) -> DOMString;
    fn SetSize(&mut self, _size: DOMString) -> ErrorResult;
    fn Width(&self) -> DOMString;
    fn SetWidth(&mut self, _width: DOMString) -> ErrorResult;
}

impl<'a> HTMLHRElementMethods for JSRef<'a, HTMLHRElement> {
    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&mut self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Color(&self) -> DOMString {
        "".to_owned()
    }

    fn SetColor(&mut self, _color: DOMString) -> ErrorResult {
        Ok(())
    }

    fn NoShade(&self) -> bool {
        false
    }

    fn SetNoShade(&self, _no_shade: bool) -> ErrorResult {
        Ok(())
    }

    fn Size(&self) -> DOMString {
        "".to_owned()
    }

    fn SetSize(&mut self, _size: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Width(&self) -> DOMString {
        "".to_owned()
    }

    fn SetWidth(&mut self, _width: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLHRElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLHRElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLHRElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLHRElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLHRElement {
    pub htmlelement: HTMLElement,
}

impl HTMLHRElementDerived for EventTarget {
    fn is_htmlhrelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLHRElementTypeId))
    }
}

impl HTMLHRElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLHRElement {
        HTMLHRElement {
            htmlelement: HTMLElement::new_inherited(HTMLHRElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLHRElement> {
        let element = HTMLHRElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLHRElementBinding::Wrap)
    }
}

pub trait HTMLHRElementMethods {
    fn Align(&self) -> DOMString;
    fn SetAlign(&self, _align: DOMString) -> ErrorResult;
    fn Color(&self) -> DOMString;
    fn SetColor(&self, _color: DOMString) -> ErrorResult;
    fn NoShade(&self) -> bool;
    fn SetNoShade(&self, _no_shade: bool) -> ErrorResult;
    fn Size(&self) -> DOMString;
    fn SetSize(&self, _size: DOMString) -> ErrorResult;
    fn Width(&self) -> DOMString;
    fn SetWidth(&self, _width: DOMString) -> ErrorResult;
}

impl<'a> HTMLHRElementMethods for JSRef<'a, HTMLHRElement> {
    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Color(&self) -> DOMString {
        "".to_owned()
    }

    fn SetColor(&self, _color: DOMString) -> ErrorResult {
        Ok(())
    }

    fn NoShade(&self) -> bool {
        false
    }

    fn SetNoShade(&self, _no_shade: bool) -> ErrorResult {
        Ok(())
    }

    fn Size(&self) -> DOMString {
        "".to_owned()
    }

    fn SetSize(&self, _size: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Width(&self) -> DOMString {
        "".to_owned()
    }

    fn SetWidth(&self, _width: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//#[cfg(test)] use racer::testutils::{rejustify, slice};

pub fn rejustify(src: &str) -> String {
    let s = &src[1..]; // remove the newline
    let mut sb = String::new();
    for l in s.lines() {
        let tabless = &l[4..];
        sb.push_str(tabless);
        if tabless.len() != 0 {
            sb.push_str("\n");
        }
    }
    let newlen = sb.len()-1; // remove the trailing newline
    sb.truncate(newlen);
    sb
}

pub fn slice(src: &str, (begin, end): (usize, usize)) -> &str{
    &src[begin..end]
}

enum State {
    StateCode,
    StateComment,
    StateCommentBlock,
    StateString,
    StateFinished
}

pub struct CodeIndicesIter<'a> {
    src: &'a str,
    start: usize,
    pos: usize,
    nesting_level: usize,
    state: State
}

impl<'a> Iterator for CodeIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {
        match self.state {
            State::StateCode => code(self),
            State::StateComment => comment(self),
            State::StateCommentBlock  => comment_block(self),
            State::StateString => string(self),
            State::StateFinished => None
        }
    }
}

fn code(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {

    // previous character to handle comments
    let mut prev = if self_.pos > 0 { self_.src.char_at(self_.pos-1) } else { ' ' };

    for (i, c) in self_.src[self_.pos..].chars().enumerate() {
        match c {
            '/' if prev == '/' => {
                return code_return(self_, i, State::StateComment, i-1);
            },
            '*' if prev == '/' => {
                self_.nesting_level = 0;
                return code_return(self_, i, State::StateCommentBlock, i-1);
            },
            '"' => {
                // include the dblquote in the code
                return code_return(self_, i, State::StateString, i+1);
            },
            _ => { prev = c; }
        }
    }

    self_.state = State::StateFinished;
    Some((self_.start, self_.src.len()))
}

fn code_return(self_: &mut CodeIndicesIter, i: usize, state: State, inner_end: usize)
        -> Option<(usize,usize)>{
    let res = Some((self_.start, self_.pos+inner_end));
    self_.pos += i+1;
    self_.start = self_.pos;
    self_.state = state;
    return res;
}

fn comment(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {
    for (i, c) in self_.src[self_.pos..].chars().enumerate() {
        if c == '\n' {
            self_.pos += i+1;
            self_.start = self_.pos;
            self_.state = State::StateCode;
            return code(self_);
        }
    }
    self_.state = State::StateFinished;
    Some((self_.start, self_.src.len()))
}

fn comment_block(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {

    // previous character to handle comments
    let mut prev = if self_.pos > 0 { self_.src.char_at(self_.pos-1) } else { ' ' };

    for (i, c) in self_.src[self_.pos..].chars().enumerate() {
        match c {
            '/' if prev == '*' => {
                if self_.nesting_level == 0 {
                    self_.pos += i+1;
                    self_.start = self_.pos;
                    self_.state = State::StateCode;
                    return code(self_);
                } else {
                    self_.nesting_level -= 1;
                }
            },
            '*' if prev == '/' => {
                self_.nesting_level += 1;
            },
            _ => { prev = c; }
        }
    }
    self_.state = State::StateFinished;
    return Some((self_.start, self_.src.len()));
}

fn string(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {
    let mut is_escaped = false;
    for (i, c) in self_.src[self_.pos..].chars().enumerate() {
        match c {
            '"' if !is_escaped  => {
                self_.start = self_.pos+i;  // include the dblquote as code
                self_.pos = self_.start+1;
                self_.state = State::StateCode;
                return code(self_);
            },
            '\\' => { is_escaped = !is_escaped; },
            _ => { if is_escaped {is_escaped = false;} }
        }
    }
    self_.state = State::StateFinished;
    return Some((self_.start, self_.src.len()));
}

/// Returns indices of chunks of code (minus comments and string contents)
pub fn code_chunks<'a>(src: &'a str) -> CodeIndicesIter<'a> {
    CodeIndicesIter { src: src, start: 0, pos: 0, state: State::StateCode, nesting_level: 0 }
}

#[test]
fn removes_a_comment() {
    let src = &rejustify("
    this is some code // this is a comment
    some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents() {
    let src = &rejustify("
    this is some code \"this is a string\" more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents_with_a_comment_in_it() {
    let src = &rejustify("
    this is some code \"string with a // fake comment \" more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_a_comment_with_a_dbl_quote_in_it() {
    let src = &rejustify("
    this is some code // comment with \" double quote
    some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_multiline_comment() {
    let src = &rejustify("
    this is some code /* this is a
    \"multiline\" comment */some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_nesting_of_block_comments() {
    let src = &rejustify("
    this is some code /* nested /* block */ comment */ some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!(" some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with a \\\" escaped dblquote fake comment \" more code
    ")[];

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_slash_before_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with an escaped slash, so dbl quote does end the string after all \\\\\" more code
    ")[];

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_tricky_bit_from_str_rs() {
    let src = &rejustify("
        before(\"\\\\\'\\\\\\\"\\\\\\\\\");
        more_code(\" skip me \")
    ")[];

    for (start,end) in code_chunks(src) {
        println!("BLOB |{}|",&src[start..end]);
        if (&src[start..end]).contains("skip me") {
            panic!("{}", &src[start..end]);
        }
    }
}

// fn main() {
//     use std::io::BufferedReader;
//     use std::io::File;
//     use std::str;

//     //let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/prelude.rs"))).read_to_end().unwrap();
//     //let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/prelude.rs"))).read_to_end().unwrap();
//     let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libcollections/str.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in code_chunks(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<commit_msg>Revert back to bytes instead of chars<commit_after>//#[cfg(test)] use racer::testutils::{rejustify, slice};

pub fn rejustify(src: &str) -> String {
    let s = &src[1..]; // remove the newline
    let mut sb = String::new();
    for l in s.lines() {
        let tabless = &l[4..];
        sb.push_str(tabless);
        if tabless.len() != 0 {
            sb.push_str("\n");
        }
    }
    let newlen = sb.len()-1; // remove the trailing newline
    sb.truncate(newlen);
    sb
}

pub fn slice(src: &str, (begin, end): (usize, usize)) -> &str{
    &src[begin..end]
}

enum State {
    StateCode,
    StateComment,
    StateCommentBlock,
    StateString,
    StateFinished
}

pub struct CodeIndicesIter<'a> {
    src: &'a str,
    start: usize,
    pos: usize,
    nesting_level: usize,
    state: State
}

impl<'a> Iterator for CodeIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {
        match self.state {
            State::StateCode => code(self),
            State::StateComment => comment(self),
            State::StateCommentBlock  => comment_block(self),
            State::StateString => string(self),
            State::StateFinished => None
        }
    }
}

fn code(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {

    let src_bytes = self_.src.as_bytes();
    let mut is_prev_slash = self_.pos > 0 && src_bytes[self_.pos-1] == b'/';

    for (i, &b) in src_bytes[self_.pos..].iter().enumerate() {
        match b {
            b'/' => {
                if is_prev_slash {
                    return code_return(self_, i, State::StateComment, i-1);
                }
                is_prev_slash = true;
            },
            b'*' if is_prev_slash => {
                self_.nesting_level = 0;
                return code_return(self_, i, State::StateCommentBlock, i-1);
            },
            b'"' => {
                // include the dblquote in the code
                return code_return(self_, i, State::StateString, i+1);
            },
            _ => { is_prev_slash = false; }
        }
    }

    self_.state = State::StateFinished;
    Some((self_.start, src_bytes.len()))
}

fn code_return(self_: &mut CodeIndicesIter, i: usize, state: State, inner_end: usize)
        -> Option<(usize,usize)>{
    let res = Some((self_.start, self_.pos+inner_end));
    self_.pos += i+1;
    self_.start = self_.pos;
    self_.state = state;
    return res;
}

fn comment(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {
    let src_bytes = self_.src.as_bytes();
    for (i, &b) in src_bytes[self_.pos..].iter().enumerate() {
        if b == b'\n' {
            self_.pos += i+1;
            self_.start = self_.pos;
            self_.state = State::StateCode;
            return code(self_);
        }
    }
    self_.state = State::StateFinished;
    Some((self_.start, src_bytes.len()))
}

fn comment_block(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {

    let src_bytes = self_.src.as_bytes();
    // previous character
    let mut prev = if self_.pos > 0 { src_bytes[self_.pos-1] } else { b' ' };

    for (i, &b) in src_bytes[self_.pos..].iter().enumerate() {
        match b {
            b'/' if prev == b'*' => {
                if self_.nesting_level == 0 {
                    self_.pos += i+1;
                    self_.start = self_.pos;
                    self_.state = State::StateCode;
                    return code(self_);
                } else {
                    self_.nesting_level -= 1;
                }
            },
            b'*' if prev == b'/' => {
                self_.nesting_level += 1;
            },
            _ => { prev = b; }
        }
    }
    self_.state = State::StateFinished;
    return Some((self_.start, src_bytes.len()));
}

fn string(self_: &mut CodeIndicesIter) -> Option<(usize,usize)> {
    let src_bytes = self_.src.as_bytes();
    let mut is_escaped = false;
    for (i, &b) in src_bytes[self_.pos..].iter().enumerate() {
        match b {
            b'"' if !is_escaped  => {
                self_.start = self_.pos+i;  // include the dblquote as code
                self_.pos = self_.start+1;
                self_.state = State::StateCode;
                return code(self_);
            },
            b'\\' => { is_escaped = !is_escaped; },
            _ => { if is_escaped {is_escaped = false;} }
        }
    }
    self_.state = State::StateFinished;
    return Some((self_.start, src_bytes.len()));
}

/// Returns indices of chunks of code (minus comments and string contents)
pub fn code_chunks<'a>(src: &'a str) -> CodeIndicesIter<'a> {
    CodeIndicesIter { src: src, start: 0, pos: 0, state: State::StateCode, nesting_level: 0 }
}

#[test]
fn removes_a_comment() {
    let src = &rejustify("
    this is some code // this is a comment
    some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents() {
    let src = &rejustify("
    this is some code \"this is a string\" more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents_with_a_comment_in_it() {
    let src = &rejustify("
    this is some code \"string with a // fake comment \" more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_a_comment_with_a_dbl_quote_in_it() {
    let src = &rejustify("
    this is some code // comment with \" double quote
    some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_multiline_comment() {
    let src = &rejustify("
    this is some code /* this is a
    \"multiline\" comment */some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_nesting_of_block_comments() {
    let src = &rejustify("
    this is some code /* nested /* block */ comment */ some more code
    ")[];
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!(" some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with a \\\" escaped dblquote fake comment \" more code
    ")[];

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_slash_before_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with an escaped slash, so dbl quote does end the string after all \\\\\" more code
    ")[];

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_tricky_bit_from_str_rs() {
    let src = &rejustify("
        before(\"\\\\\'\\\\\\\"\\\\\\\\\");
        more_code(\" skip me \")
    ")[];

    for (start,end) in code_chunks(src) {
        println!("BLOB |{}|",&src[start..end]);
        if (&src[start..end]).contains("skip me") {
            panic!("{}", &src[start..end]);
        }
    }
}

// fn main() {
//     use std::io::BufferedReader;
//     use std::io::File;
//     use std::str;

//     //let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/prelude.rs"))).read_to_end().unwrap();
//     //let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/prelude.rs"))).read_to_end().unwrap();
//     let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libcollections/str.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in code_chunks(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<|endoftext|>