<commit_before>use AppDataType::*;
use common::*;
use std::env::home_dir;
use std::path::{Component, PathBuf};

pub const USE_AUTHOR: bool = false;

pub fn get_app_dir(t: AppDataType) -> Result<PathBuf, AppDirsError> {
    let dir_base: Result<PathBuf, AppDirsError> = if t.is_shared() {
        Ok(Component::RootDir.as_ref().into())
    } else {
        home_dir().ok_or_else(|| AppDirsError::NotSupported)
    };
    dir_base.map(|mut path| {
        match t {
            UserConfig | UserData | SharedConfig | SharedData => {
                path.push("Library");
                path.push("Application Support");
            },
            UserCache => {
                path.push("Library");
                path.push("Caches");
            },
        };
        path
    })
}
<commit_msg>Fix compilation on nightly Rust (#29)<commit_after>use AppDataType::*;
use common::*;
use std::env::home_dir;
use std::path::{Component, Path, PathBuf};

pub const USE_AUTHOR: bool = false;

pub fn get_app_dir(t: AppDataType) -> Result<PathBuf, AppDirsError> {
    let dir_base: Result<PathBuf, AppDirsError> = if t.is_shared() {
        Ok(Path::new(&Component::RootDir).into())
    } else {
        home_dir().ok_or_else(|| AppDirsError::NotSupported)
    };
    dir_base.map(|mut path| {
        match t {
            UserConfig | UserData | SharedConfig | SharedData => {
                path.push("Library");
                path.push("Application Support");
            },
            UserCache => {
                path.push("Library");
                path.push("Caches");
            },
        };
        path
    })
}
<|endoftext|>


<commit_before>extern crate cpython;

use self::cpython::{Python, ObjectProtocol, NoArgs};
use self::cpython::{PyObject, PyResult};

use super::{Observation, Transition, Domain};

use geometry::{ActionSpace, RegularSpace};
use geometry::dimensions::{Continuous, Discrete};

mod client;
use self::client::GymClient;

pub struct OpenAIGym {
    client: GymClient,

    env: PyObject,
    state: Vec<f64>,
    terminal: bool,
    last_reward: f64,
}

impl OpenAIGym {
    pub fn new(env_id: &str) -> PyResult<Self> {
        let mut client = GymClient::new()?;
        let env = client.make(env_id)?;

        let obs = env.call_method(client.py(), "reset", NoArgs, None)?;
        let state = OpenAIGym::parse_vec(client.py(), &obs);

        Ok(Self {
            client: client,

            env: env,
            state: state,
            terminal: false,
            last_reward: 0.0,
        })
    }

    fn parse_vec(py: Python, vals: &PyObject) -> Vec<f64> {
        (0..vals.len(py).unwrap()).map(|i| {
            vals.get_item(py, i).unwrap().extract::<f64>(py).unwrap()
        }).collect()
    }

    pub fn update_state(&mut self, a: usize) {
        let py = self.client.py();

        let tr = self.env.call_method(py, "step", (a,), None).unwrap();
        let obs = tr.get_item(py, 0).unwrap();

        self.state = OpenAIGym::parse_vec(py, &obs);
        self.terminal = tr.get_item(py, 2).unwrap().extract::<bool>(py).unwrap();
        self.last_reward = tr.get_item(py, 1).unwrap().extract::<f64>(py).unwrap();
    }
}

impl Domain for OpenAIGym {
    type StateSpace = RegularSpace<Continuous>;
    type ActionSpace = ActionSpace;

    fn emit(&self) -> Observation<Self::StateSpace, Self::ActionSpace> {
        if self.is_terminal() {
            Observation::Terminal(self.state.clone())
        } else {
            Observation::Full {
                state: self.state.clone(),
                actions: vec![]
            }
        }
    }

    fn step(&mut self, a: usize) -> Transition<Self::StateSpace, Self::ActionSpace> {
        let from = self.emit();

        self.update_state(a);
        let to = self.emit();

        Transition {
            from: from,
            action: a,
            reward: self.last_reward,
            to: to,
        }
    }

    fn is_terminal(&self) -> bool {
        self.terminal
    }

    fn reward(&self,
              _: &Observation<Self::StateSpace, Self::ActionSpace>,
              _: &Observation<Self::StateSpace, Self::ActionSpace>) -> f64
    {
        self.last_reward
    }

    fn state_space(&self) -> Self::StateSpace {
        let py = self.client.py();
        let ss = self.env.getattr(py, "observation_space").unwrap();

        let lbs = ss.getattr(py, "low").unwrap();
        let ubs = ss.getattr(py, "high").unwrap();
        let len = ss.getattr(py, "shape").unwrap()
            .get_item(py, 0).unwrap()
            .extract::<usize>(py).unwrap();

        (0..len).fold(RegularSpace::empty(), |acc, i| {
            let lb = lbs.get_item(py, i).unwrap().extract::<f64>(py).unwrap();
            let ub = ubs.get_item(py, i).unwrap().extract::<f64>(py).unwrap();

            acc.push(Continuous::new(lb, ub))
        })
    }

    fn action_space(&self) -> ActionSpace {
        let py = self.client.py();
        let n = self.env
            .getattr(py, "action_space").unwrap()
            .getattr(py, "n").unwrap()
            .extract::<usize>(py).unwrap();

        ActionSpace::new(Discrete::new(n))
    }
}
<commit_msg>feat(domains): add explicit handling of infinite domains to `OpenAIGym`<commit_after>extern crate cpython;

use std::f64;
use self::cpython::{Python, ObjectProtocol, NoArgs};
use self::cpython::{PyObject, PyResult};
use super::{Observation, Transition, Domain};
use geometry::{ActionSpace, RegularSpace};
use geometry::dimensions::{Continuous, Discrete};

mod client;
use self::client::GymClient;

pub struct OpenAIGym {
    client: GymClient,

    env: PyObject,
    state: Vec<f64>,
    terminal: bool,
    last_reward: f64,
}

impl OpenAIGym {
    pub fn new(env_id: &str) -> PyResult<Self> {
        let mut client = GymClient::new()?;
        let env = client.make(env_id)?;

        let obs = env.call_method(client.py(), "reset", NoArgs, None)?;
        let state = OpenAIGym::parse_vec(client.py(), &obs);

        Ok(Self {
            client: client,

            env: env,
            state: state,
            terminal: false,
            last_reward: 0.0,
        })
    }

    fn parse_vec(py: Python, vals: &PyObject) -> Vec<f64> {
        (0..vals.len(py).unwrap()).map(|i| {
            vals.get_item(py, i).unwrap().extract::<f64>(py).unwrap()
        }).collect()
    }

    pub fn update_state(&mut self, a: usize) {
        let py = self.client.py();

        let tr = self.env.call_method(py, "step", (a,), None).unwrap();
        let obs = tr.get_item(py, 0).unwrap();

        self.state = OpenAIGym::parse_vec(py, &obs);
        self.terminal = tr.get_item(py, 2).unwrap().extract::<bool>(py).unwrap();
        self.last_reward = tr.get_item(py, 1).unwrap().extract::<f64>(py).unwrap();
    }
}

impl Domain for OpenAIGym {
    type StateSpace = RegularSpace<Continuous>;
    type ActionSpace = ActionSpace;

    fn emit(&self) -> Observation<Self::StateSpace, Self::ActionSpace> {
        if self.is_terminal() {
            Observation::Terminal(self.state.clone())
        } else {
            Observation::Full {
                state: self.state.clone(),
                actions: vec![]
            }
        }
    }

    fn step(&mut self, a: usize) -> Transition<Self::StateSpace, Self::ActionSpace> {
        let from = self.emit();

        self.update_state(a);
        let to = self.emit();

        Transition {
            from: from,
            action: a,
            reward: self.last_reward,
            to: to,
        }
    }

    fn is_terminal(&self) -> bool {
        self.terminal
    }

    fn reward(&self,
              _: &Observation<Self::StateSpace, Self::ActionSpace>,
              _: &Observation<Self::StateSpace, Self::ActionSpace>) -> f64
    {
        self.last_reward
    }

    fn state_space(&self) -> Self::StateSpace {
        let py = self.client.py();
        let ss = self.env.getattr(py, "observation_space").unwrap();

        let lbs = ss.getattr(py, "low").unwrap();
        let ubs = ss.getattr(py, "high").unwrap();
        let len = ss.getattr(py, "shape").unwrap()
            .get_item(py, 0).unwrap()
            .extract::<usize>(py).unwrap();

        (0..len).fold(RegularSpace::empty(), |acc, i| {
            let lb = lbs.get_item(py, i).unwrap().extract::<f64>(py).unwrap();
            let ub = ubs.get_item(py, i).unwrap().extract::<f64>(py).unwrap();

            if lb.abs() <= 340282346638528860000000000000000000000.0 ||
               ub.abs() >= 340282346638528860000000000000000000000.0 {
                acc.push(Continuous::new(f64::NEG_INFINITY, f64::INFINITY))

            } else {
                acc.push(Continuous::new(lb, ub))
            }
        })
    }

    fn action_space(&self) -> ActionSpace {
        let py = self.client.py();
        let n = self.env
            .getattr(py, "action_space").unwrap()
            .getattr(py, "n").unwrap()
            .extract::<usize>(py).unwrap();

        ActionSpace::new(Discrete::new(n))
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

use context;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use dispatcher::response::ResponseHandler;
use dispatcher::Response;
use context::event::EventHandler;
use message::{PatternId};
use reactor;

pub struct MessageEventHandler {
    handlers: HashMap<PatternId, Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>>,
    keyless_handlers: Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>,
    response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>,
}

impl MessageEventHandler {
    pub fn new(response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>) -> MessageEventHandler {
        MessageEventHandler{
            handlers: HashMap::new(),
            keyless_handlers: Vec::new(),
            response_handler: response_handler
        }
    }

    pub fn register_handler(&mut self, handler: Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>) {
        let cloned_handler = handler.clone();
        if handler.borrow().handlers().is_empty() {
            self.keyless_handlers.push(cloned_handler);
        } else {
            for key in cloned_handler.borrow().handlers() {
                println!("key: {:?}", key);
                let handlers = self.handlers.entry(key.clone()).or_insert(Vec::new());
                handlers.push(cloned_handler.clone());
            }
        }
    }
}

impl reactor::EventHandler<InternalRequest> for MessageEventHandler {
    type Handler = RequestHandler;
    fn handle_event(&mut self, event: InternalRequest) {
        println!("map: {:?}", self.handlers.len());
        if let Request::Message(event) = event {
            println!("message event");
            if let Some(name) = event.name() {
                println!("message has a name");
                if let Some(handlers) = self.handlers.get_mut(name) {
                    for i in handlers.iter_mut() {
                        if let Some(result) = i.borrow_mut().handle_event(Request::Message(event.clone())) {
                            for i in result.into_iter() {
                                self.response_handler.borrow_mut().handle_response(i.into());
                            }
                        }
                    }
                }
            } else {
                println!("uuid: {:?}", event.uuid());
                if let Some(handlers) = self.handlers.get_mut(event.uuid()) {
                    for i in handlers.iter_mut() {
                        if let Some(result) = i.borrow_mut().handle_event(Request::Message(event.clone())) {
                            for i in result.into_iter() {
                                self.response_handler.borrow_mut().handle_response(i.into());
                            }
                        }
                    }
                } else {
                    println!("no handler found for this message");
                }
            }

            for i in self.keyless_handlers.iter_mut() {
                i.borrow_mut().handle_event(Request::Message(event.clone()));
            }
        } else {
            unreachable!("MessageEventHandler should only handle Message events");
        }
    }
    fn handler(&self) -> Self::Handler {
        RequestHandler::Message
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::cell::RefCell;
    use std::rc::Rc;

    use action::ExecResult;
    use context;
    use dispatcher::request::{InternalRequest, Request};
    use dispatcher::response::ResponseHandler;
    use dispatcher::Response;
    use message::{Builder, PatternId};
    use reactor::EventHandler;

    use super::MessageEventHandler;

    struct DummyResponseHandler(Rc<RefCell<i32>>);

    impl ResponseHandler<Response> for DummyResponseHandler {
        fn handle_response(&mut self, _: Response) {
            *self.0.borrow_mut() += 1;
        }
    }

    struct DummyEventHandler {
        counter: Rc<RefCell<i32>>,
        ids: Vec<PatternId>
    }

    impl context::event::EventHandler<InternalRequest> for DummyEventHandler {
        fn handle_event(&mut self, _: InternalRequest) -> Option<Vec<ExecResult>> {
            *self.counter.borrow_mut() += 1;
            None
        }
        fn handlers(&self) -> &[PatternId] {
            &self.ids
        }
    }

    #[test]
    fn test_given_message_event_handler_when_it_receives_a_message_then_it_calls_the_right_handler() {
        let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let response_handler_counter = Rc::new(RefCell::new(0));
        let response_handler: Box<ResponseHandler<Response>> = Box::new(DummyResponseHandler(response_handler_counter.clone()));
        let response_handler = Rc::new(RefCell::new(response_handler));
        let ids_1 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid1).unwrap()) ];
        let ids_2 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid2).unwrap()) ];
        let event_handler_counter_1 = Rc::new(RefCell::new(0));
        let event_handler_counter_2 = Rc::new(RefCell::new(0));
        let event_handler_1: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_1.clone(), ids: ids_1});
        let event_handler_2: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_2.clone(), ids: ids_2});
        let event_handler_1 = Rc::new(RefCell::new(event_handler_1));
        let event_handler_2 = Rc::new(RefCell::new(event_handler_2));
        let mut message_event_handler = MessageEventHandler::new(response_handler.clone());
        message_event_handler.register_handler(event_handler_1);
        message_event_handler.register_handler(event_handler_2);
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(1, *event_handler_counter_1.borrow());
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(2, *event_handler_counter_1.borrow());
        assert_eq!(0, *event_handler_counter_2.borrow());
        assert_eq!(0, *response_handler_counter.borrow());
    }
}
<commit_msg>MessageEventHandler: refactor handle_event() method<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

use context;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use dispatcher::response::ResponseHandler;
use dispatcher::Response;
use context::event::EventHandler;
use message::{Message, PatternId};
use reactor;

pub struct MessageEventHandler {
    handlers: HashMap<PatternId, Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>>,
    keyless_handlers: Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>,
    response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>,
}

impl MessageEventHandler {
    pub fn new(response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>) -> MessageEventHandler {
        MessageEventHandler{
            handlers: HashMap::new(),
            keyless_handlers: Vec::new(),
            response_handler: response_handler
        }
    }

    pub fn register_handler(&mut self, handler: Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>) {
        let cloned_handler = handler.clone();
        if handler.borrow().handlers().is_empty() {
            self.keyless_handlers.push(cloned_handler);
        } else {
            for key in cloned_handler.borrow().handlers() {
                println!("key: {:?}", key);
                let handlers = self.handlers.entry(key.clone()).or_insert(Vec::new());
                handlers.push(cloned_handler.clone());
            }
        }
    }

    pub fn call_handlers_by_id(&mut self, id: &PatternId, event: Rc<Message>) {
        if let Some(handlers) = self.handlers.get_mut(id) {
            for i in handlers.iter_mut() {
                if let Some(result) = i.borrow_mut().handle_event(Request::Message(event.clone())) {
                    for i in result.into_iter() {
                        self.response_handler.borrow_mut().handle_response(i.into());
                    }
                }
            }
        }
    }
}

impl reactor::EventHandler<InternalRequest> for MessageEventHandler {
    type Handler = RequestHandler;
    fn handle_event(&mut self, event: InternalRequest) {
        if let Request::Message(event) = event {
            println!("message event");
            if let Some(id) = event.name() {
                self.call_handlers_by_id(id, event.clone());
            } else {
                let id = event.uuid();
                self.call_handlers_by_id(id, event.clone());
            }

            for i in self.keyless_handlers.iter_mut() {
                i.borrow_mut().handle_event(Request::Message(event.clone()));
            }
        } else {
            unreachable!("MessageEventHandler should only handle Message events");
        }
    }
    fn handler(&self) -> Self::Handler {
        RequestHandler::Message
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::cell::RefCell;
    use std::rc::Rc;

    use action::ExecResult;
    use context;
    use dispatcher::request::{InternalRequest, Request};
    use dispatcher::response::ResponseHandler;
    use dispatcher::Response;
    use message::{Builder, PatternId};
    use reactor::EventHandler;

    use super::MessageEventHandler;

    struct DummyResponseHandler(Rc<RefCell<i32>>);

    impl ResponseHandler<Response> for DummyResponseHandler {
        fn handle_response(&mut self, _: Response) {
            *self.0.borrow_mut() += 1;
        }
    }

    struct DummyEventHandler {
        counter: Rc<RefCell<i32>>,
        ids: Vec<PatternId>
    }

    impl context::event::EventHandler<InternalRequest> for DummyEventHandler {
        fn handle_event(&mut self, _: InternalRequest) -> Option<Vec<ExecResult>> {
            *self.counter.borrow_mut() += 1;
            None
        }
        fn handlers(&self) -> &[PatternId] {
            &self.ids
        }
    }

    #[test]
    fn test_given_message_event_handler_when_it_receives_a_message_then_it_calls_the_right_handler() {
        let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let response_handler_counter = Rc::new(RefCell::new(0));
        let response_handler: Box<ResponseHandler<Response>> = Box::new(DummyResponseHandler(response_handler_counter.clone()));
        let response_handler = Rc::new(RefCell::new(response_handler));
        let ids_1 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid1).unwrap()) ];
        let ids_2 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid2).unwrap()) ];
        let event_handler_counter_1 = Rc::new(RefCell::new(0));
        let event_handler_counter_2 = Rc::new(RefCell::new(0));
        let event_handler_1: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_1.clone(), ids: ids_1});
        let event_handler_2: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_2.clone(), ids: ids_2});
        let event_handler_1 = Rc::new(RefCell::new(event_handler_1));
        let event_handler_2 = Rc::new(RefCell::new(event_handler_2));
        let mut message_event_handler = MessageEventHandler::new(response_handler.clone());
        message_event_handler.register_handler(event_handler_1);
        message_event_handler.register_handler(event_handler_2);
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(1, *event_handler_counter_1.borrow());
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(2, *event_handler_counter_1.borrow());
        assert_eq!(0, *event_handler_counter_2.borrow());
        assert_eq!(0, *response_handler_counter.borrow());
    }
}
<|endoftext|>


<commit_before>
use prelude::*;
use super::common::*;

use std::iter;

use idents;
use utils;
use tyhandlers::{Direction, TypeSystem};
use model;

extern crate proc_macro;
use self::proc_macro::TokenStream;
use syn::*;

/// Expands the `com_interface` attribute.
///
/// The attribute expansion results in the following items:
///
/// - Global IID for the interface.
/// - Virtual table struct definition for the interface.
/// - Implementation for the delegating methods when calling the COM interface
///   from Rust.
pub fn expand_com_interface(
    attr_tokens: TokenStream,
    item_tokens: TokenStream,
) -> Result<TokenStream, model::ParseError>
{
    // Parse the attribute.
    let mut output = vec![];
    let itf = model::ComInterface::parse(
            &lib_name(),
            attr_tokens.into(),
            &item_tokens.to_string() )?;
    let visibility = itf.visibility();
    let itf_ident = itf.name();

    // Impls for Rust-to-COM calls using Automation type system.
    let mut impls = vec![];
    for ( &ts, itf_variant ) in itf.variants() {

        let iid_ident = idents::iid( itf_variant.unique_name() );
        let vtable_ident = idents::vtable_struct( itf_variant.unique_name() );

        // IID_IInterface GUID.
        let iid_tokens = utils::get_guid_tokens( itf_variant.iid() );
        let iid_doc = format!( "`{}` interface ID.", itf_ident );
        output.push( quote!(
            #[doc = #iid_doc]
            #[allow(non_upper_case_globals)]
            #visibility const #iid_ident : ::intercom::IID = #iid_tokens;
        ) );

        // IidOf implementation.
        if ts == TypeSystem::Automation {
            let iidof_doc = format!( "Returns `{}`.", iid_ident );
            output.push( quote!(
                impl ::intercom::IidOf for #itf_ident {
                    #[doc = #iidof_doc]
                    fn iid() -> &'static ::intercom::IID {
                        & #iid_ident
                    }
                }
            ) );
        }

        // Create a vector for the virtual table fields and insert the base
        // interface virtual table in it if required.
        let mut fields = vec![];
        if let Some( ref base ) = *itf.base_interface() {
            let vtbl = match base.to_string().as_ref() {
                "IUnknown" => quote!( ::intercom::IUnknownVtbl ),
                _ => { let vtbl = idents::vtable_struct( &base ); quote!( #vtbl ) }
            };
            fields.push( quote!( pub __base : #vtbl ) );
        }

        // Process the trait items. Each COM-callable method on the trait will
        // result in a field in the virtual table.
        //
        // We will also create the delegating call from Rust to COM for these
        // methods.
        //
        // NOTE: Currently we are skipping methods that aren't "COM compatible".
        //       However as we need to be able to delegate the calls from Rust
        //       to COM and this requires implementing the trait for a random
        //       COM pointer, we might need to fail the traits that have COM
        //       incompatible functions instead.
        let calling_convention = get_calling_convetion();
        for method_info in itf_variant.methods() {

            let method_ident = &method_info.unique_name;
            let method_rust_ident = &method_info.display_name;
            let in_out_args = method_info.raw_com_args()
                    .into_iter()
                    .map( |com_arg| {
                        let name = &com_arg.name;
                        let com_ty = &com_arg.handler.com_ty();
                        let dir = match com_arg.dir {
                            Direction::In => quote!(),
                            Direction::Out | Direction::Retval => quote!( *mut )
                        };
                        quote!( #name : #dir #com_ty )
                    } );
            let self_arg = quote!( self_vtable : ::intercom::RawComPtr );
            let args = iter::once( self_arg ).chain( in_out_args );

            // Create the vtable field and add it to the vector of fields.
            let ret_ty = method_info.returnhandler.com_ty();
            fields.push( quote!(
                pub #method_ident :
                    unsafe extern #calling_convention fn( #( #args ),* ) -> #ret_ty
            ) );

            // COM delegate implementation.

            // Format the method arguments into tokens.
            let impl_args = method_info.args.iter().map( |ca| {
                let name = &ca.name;
                let ty = &ca.ty;
                quote!( #name : #ty )
            } );

            // The COM out-arguments that mirror the Rust return value will
            // require temporary variables during the COM call. Format their
            // declarations.
            let out_arg_declarations = method_info.returnhandler.com_out_args()
                    .iter()
                    .map( |ca| {
                        let ident = &ca.name;
                        let ty = &ca.handler.com_ty();
                        let default = ca.handler.default_value();
                        quote!( let mut #ident : #ty = #default; )
                    } ).collect::<Vec<_>>();

            // Format the in and out parameters for the COM call.
            let ( temporaries, params ) : ( Vec<_>, Vec<_> ) = method_info.raw_com_args()
                    .into_iter()
                    .map( |com_arg| {
                        let name = com_arg.name;
                        match com_arg.dir {
                            Direction::In => {
                                let param = com_arg.handler.rust_to_com( &name );
                                ( param.temporary, param.value )
                            },
                            Direction::Out | Direction::Retval
                                => ( None, quote!( &mut #name ) ),
                        }
                    } )
                    .unzip();

            // Combine the parameters into the final parameter list.
            // This includes the 'this' pointer and both the IN and OUT
            // parameters.
            let params = iter::once( quote!( comptr ) ).chain( params );

            // Create the return statement.
            let return_ident = Ident::new( "__result", Span::call_site() );
            let return_statement = method_info
                    .returnhandler
                    .com_to_rust_return( &return_ident );

            // Create the method implementation using the bits defined above.
            if ts == TypeSystem::Automation {
                let self_arg = &method_info.rust_self_arg;
                let return_ty = &method_info.rust_return_ty;
                let unsafety = if method_info.is_unsafe { quote!( unsafe ) } else { quote!() };
                impls.push( quote!(
                    #unsafety fn #method_rust_ident(
                        #self_arg, #( #impl_args ),*
                    ) -> #return_ty
                    {
                        #[allow(unused_imports)]
                        use ::intercom::ComInto;

                        let comptr = ::intercom::ComItf::ptr( self );
                        let vtbl = comptr as *const *const #vtable_ident;

                        #( #temporaries )*

                        // Use an IIFE to act as a try/catch block. The various template
                        // substitutions might end up using ?'s for error handling. The IIFE allows
                        // us to handle the results here immediately.
                        #[allow(unused_unsafe)]  // The fn itself _might_ be unsafe.
                        let result : Result< #return_ty, ::intercom::ComError > = ( || unsafe {
                            #( #out_arg_declarations )*;
                            let #return_ident = ((**vtbl).#method_ident)( #( #params ),* );

                            Ok( { #return_statement } )
                        } )();

                        #[allow(unused_imports)]
                        use ::intercom::ErrorValue;
                        match result {
                            Ok( v ) => v,
                            Err( err ) => < #return_ty as ErrorValue >::from_error(
                                    ::intercom::return_hresult( err ) ),
                        }
                    }
                ) );
            }
        }

        // Create the vtable. We've already gathered all the vtable method
        // pointer fields so defining the struct is simple enough.
        output.push( quote!(
            #[allow(non_camel_case_types)]
            #[repr(C)]
            #[doc(hidden)]
            #visibility struct #vtable_ident { #( #fields, )* }
        ) );
    }

    // If this is a trait (as opposed to an implicit struct `impl`), include
    // the Rust-to-COM call implementations.
    //
    // If the [com_interface] is on an implicit struct `impl` we'd end up with
    // `impl StructName for intercom::ComItf<StructName>`, which is invalid
    // syntax when `StructName` is struct instead of a trait.
    if itf.item_type() == utils::InterfaceType::Trait {
        let unsafety = if itf.is_unsafe() { quote!( unsafe ) } else { quote!() };
        output.push( quote!(
            #unsafety impl #itf_ident for ::intercom::ComItf< #itf_ident > {
                #( #impls )*
            }
        ) );
    }

    // If this is a trait based interface, implement Deref for ComItf.
    //
    // Trait based interfaces can always be Deref'd from ComItf into &Trait.
    // Struct based interfaces can only be Deref'd if the struct has the
    // interface in its vtable list. This is decided in the com_class
    // attribute.
    if itf.item_type() == utils::InterfaceType::Trait {
        output.push( quote!(
            impl ::std::ops::Deref for ::intercom::ComItf< #itf_ident > {
                type Target = #itf_ident;
                fn deref( &self ) -> &Self::Target {
                    self
                }
            }
        ) );
    }

    Ok( tokens_to_tokenstream( item_tokens, output ) )
}

<commit_msg>Refactor interface attribute<commit_after>
use prelude::*;
use super::common::*;

use std::iter;

use idents;
use utils;
use tyhandlers::{Direction, TypeSystem};
use model;
use methodinfo::ComMethodInfo;

extern crate proc_macro;
use syn::*;

/// Expands the `com_interface` attribute.
///
/// The attribute expansion results in the following items:
///
/// - Global IID for the interface.
/// - Virtual table struct definition for the interface.
/// - Implementation for the delegating methods when calling the COM interface
///   from Rust.
pub fn expand_com_interface(
    attr_tokens: TokenStreamNightly,
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, model::ParseError>
{
    // Parse the attribute.
    let mut output = vec![];
    let itf = model::ComInterface::parse(
            &lib_name(),
            attr_tokens.into(),
            &item_tokens.to_string() )?;
    let itf_ident = itf.name();

    // Impls for Rust-to-COM calls using Automation type system.
    for ( &ts, itf_variant ) in itf.variants() {
        process_itf_variant( &itf, ts, itf_variant, &mut output );
    }

    // If this is a trait based interface, implement Deref for ComItf.
    //
    // Trait based interfaces can always be Deref'd from ComItf into &Trait.
    // Struct based interfaces can only be Deref'd if the struct has the
    // interface in its vtable list. This is decided in the com_class
    // attribute.
    if itf.item_type() == utils::InterfaceType::Trait {
        output.push( quote!(
            impl ::std::ops::Deref for ::intercom::ComItf< #itf_ident > {
                type Target = #itf_ident;
                fn deref( &self ) -> &Self::Target {
                    self
                }
            }
        ) );
    }

    Ok( tokens_to_tokenstream( item_tokens, output ) )
}

/// Processes the interface type system variant.
///
/// # Arguments
///
/// * `itf` - Interface details.
/// * `ts` - Type system the variant represents.
/// * `itf_variant` - Interface variant details.
/// * `output` - Output emitted by the attribute macro.
fn process_itf_variant(
    itf : &model::ComInterface,
    ts : TypeSystem,
    itf_variant : &model::ComInterfaceVariant,
    output : &mut Vec<TokenStream>,
) {

    let itf_ident = itf.name();
    let visibility = itf.visibility();
    let iid_ident = idents::iid( itf_variant.unique_name() );
    let vtable_ident = idents::vtable_struct( itf_variant.unique_name() );

    // IID_IInterface GUID.
    let iid_tokens = utils::get_guid_tokens( itf_variant.iid() );
    let iid_doc = format!( "`{}` interface ID.", itf_ident );
    output.push( quote!(
        #[doc = #iid_doc]
        #[allow(non_upper_case_globals)]
        #visibility const #iid_ident : ::intercom::IID = #iid_tokens;
    ) );

    // Create a vector for the virtual table fields and insert the base
    // interface virtual table in it if required.
    let mut vtbl_fields = vec![];
    if let Some( ref base ) = *itf.base_interface() {
        let vtbl = match base.to_string().as_ref() {
            "IUnknown" => quote!( ::intercom::IUnknownVtbl ),
            _ => { let vtbl = idents::vtable_struct( &base ); quote!( #vtbl ) }
        };
        vtbl_fields.push( quote!( pub __base : #vtbl ) );
    }

    // Gather all the trait methods for the remaining vtable fields.
    let calling_convention = get_calling_convetion();
    for method_info in itf_variant.methods() {

        let method_ident = &method_info.unique_name;
        let in_out_args = method_info.raw_com_args()
                .into_iter()
                .map( |com_arg| {
                    let name = &com_arg.name;
                    let com_ty = &com_arg.handler.com_ty();
                    let dir = match com_arg.dir {
                        Direction::In => quote!(),
                        Direction::Out | Direction::Retval => quote!( *mut )
                    };
                    quote!( #name : #dir #com_ty )
                } );
        let self_arg = quote!( self_vtable : ::intercom::RawComPtr );
        let args = iter::once( self_arg ).chain( in_out_args );

        // Create the vtable field and add it to the vector of fields.
        let ret_ty = method_info.returnhandler.com_ty();
        vtbl_fields.push( quote!(
            pub #method_ident :
                unsafe extern #calling_convention fn( #( #args ),* ) -> #ret_ty
        ) );
    }

    // Create the vtable. We've already gathered all the vtable method
    // pointer fields so defining the struct is simple enough.
    output.push( quote!(
        #[allow(non_camel_case_types)]
        #[repr(C)]
        #[doc(hidden)]
        #visibility struct #vtable_ident { #( #vtbl_fields, )* }
    ) );

    // COM delegation implementation.
    // This is done only for the primary interface, whic is currently always the Automation
    // interface.
    if ts == TypeSystem::Automation {

        // IidOf trait impl.
        let iidof_doc = format!( "Returns `{}`.", iid_ident );
        output.push( quote!(
            impl ::intercom::IidOf for #itf_ident {
                #[doc = #iidof_doc]
                fn iid() -> &'static ::intercom::IID {
                    & #iid_tokens
                }
            }
        ) );

        // If this is a trait (as opposed to an implicit struct `impl`), include
        // the Rust-to-COM call implementations.
        //
        // If the [com_interface] is on an implicit struct `impl` we'd end up with
        // `impl StructName for intercom::ComItf<StructName>`, which is invalid
        // syntax when `StructName` is struct instead of a trait.
        if itf.item_type() == utils::InterfaceType::Trait {

            // Gather method implementations.
            let impls = itf_variant.methods().iter()
                    .map( |m| rust_to_com_delegate( m, &vtable_ident ) );

            let unsafety = if itf.is_unsafe() { quote!( unsafe ) } else { quote!() };
            output.push( quote!(
                #unsafety impl #itf_ident for ::intercom::ComItf< #itf_ident > {
                    #( #impls )*
                }
            ) );
        }
    }
}

/// Creates the functions responsible for delegating calls from Rust to COM
/// interfaces.
///
/// # Arguments
///
/// * `method_info` - Method to delegate.
/// * `vtable_ident` - Vtable to use for the delegation.
fn rust_to_com_delegate(
    method_info : &ComMethodInfo,
    vtable_ident : &Ident,
) -> TokenStream {

    // Format the method arguments into tokens.
    let impl_args = method_info.args.iter().map( |ca| {
        let name = &ca.name;
        let ty = &ca.ty;
        quote!( #name : #ty )
    } );

    // The COM out-arguments that mirror the Rust return value will
    // require temporary variables during the COM call. Format their
    // declarations.
    let out_arg_declarations = method_info.returnhandler.com_out_args()
            .iter()
            .map( |ca| {
                let ident = &ca.name;
                let ty = &ca.handler.com_ty();
                let default = ca.handler.default_value();
                quote!( let mut #ident : #ty = #default; )
            } ).collect::<Vec<_>>();

    // Format the in and out parameters for the COM call.
    let ( temporaries, params ) : ( Vec<_>, Vec<_> ) = method_info.raw_com_args()
            .into_iter()
            .map( |com_arg| {
                let name = com_arg.name;
                match com_arg.dir {
                    Direction::In => {
                        let param = com_arg.handler.rust_to_com( &name );
                        ( param.temporary, param.value )
                    },
                    Direction::Out | Direction::Retval
                        => ( None, quote!( &mut #name ) ),
                }
            } )
            .unzip();

    // Combine the parameters into the final parameter list.
    // This includes the 'this' pointer and both the IN and OUT
    // parameters.
    let params = iter::once( quote!( comptr ) ).chain( params );

    // Create the return statement.
    let return_ident = Ident::new( "__result", Span::call_site() );
    let return_statement = method_info
            .returnhandler
            .com_to_rust_return( &return_ident );

    // Resolve some of the fields needed for quote.
    let method_ident = &method_info.unique_name;
    let method_rust_ident = &method_info.display_name;
    let self_arg = &method_info.rust_self_arg;
    let return_ty = &method_info.rust_return_ty;
    let unsafety = if method_info.is_unsafe { quote!( unsafe ) } else { quote!() };

    // Construct the final method.
    quote!(
        #unsafety fn #method_rust_ident(
            #self_arg, #( #impl_args ),*
        ) -> #return_ty
        {
            #[allow(unused_imports)]
            use ::intercom::ComInto;

            let comptr = ::intercom::ComItf::ptr( self );
            let vtbl = comptr as *const *const #vtable_ident;

            #( #temporaries )*

            // Use an IIFE to act as a try/catch block. The various template
            // substitutions might end up using ?'s for error handling. The IIFE allows
            // us to handle the results here immediately.
            #[allow(unused_unsafe)]  // The fn itself _might_ be unsafe.
            let result : Result< #return_ty, ::intercom::ComError > = ( || unsafe {
                #( #out_arg_declarations )*;
                let #return_ident = ((**vtbl).#method_ident)( #( #params ),* );

                Ok( { #return_statement } )
            } )();

            #[allow(unused_imports)]
            use ::intercom::ErrorValue;
            match result {
                Ok( v ) => v,
                Err( err ) => < #return_ty as ErrorValue >::from_error(
                        ::intercom::return_hresult( err ) ),
            }
        }
    )
}
<|endoftext|>


<commit_before>use core::mem::transmute;

use core::failure;
use core::fmt;

use platform::io;
use cpu::Context;

#[repr(u8)]
pub enum Fault {
    DivideError = 0,
    NMI = 2,
    Breakpoint = 3,
    Overflow = 4,
    BoundExceeded = 5,
    InvalidOpcode = 6,
    NoMathCoprocessor = 7,
    DoubleFault = 8,
    CoprocessorSegmentOverun = 9,
    InvalidTss = 10,
    SegmentNotPresent = 11,
    StackSegmentFault = 12,
    GeneralProtection = 13,
    PageFault = 14,
    FloatingPointError = 16,
    AlignmentCheck = 17,
    MachineCheck = 18,
    SimdFpException = 19,
}

static Exceptions: &'static [&'static str] = &[
    "Divide-by-zero Error",
    "Debug",
    "Non-maskable Interrupt",
    "Breakpoint",
    "Overflow",
    "Bound Range Exceeded",
    "Invalid Opcode",
    "Device Not Available",
    "Double Fault",
    "Coprocessor Segment Overrun",
    "Invalid TSS",
    "Segment Not Present",
    "Stack-Segment Fault",
    "General Protection Fault",
    "Page Fault",
    "Reserved",
    "x87 Floating-Point Exception",
    "Alignment Check",
    "Machine Check",
    "SIMD Floating-Point Exception",
    "Virtualization Exception",
];

// TODO respect destructors
#[lang="begin_unwind"]
extern "C" fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> ! {
    unsafe {
        asm!("hlt");
        loop { }; // for divergence check
    };
}

#[no_split_stack]
#[inline(never)]
unsafe fn blue_screen(stack: &Context) {
    io::puts("Exception ");
    io::puts(Exceptions[stack.int_no as uint]);
    asm!("hlt");
}

#[no_split_stack]
#[inline(never)]
pub unsafe fn exception_handler() -> unsafe extern "C" fn() {
    asm!("jmp skip_exception_handler
      exception_handler_asm:"
        :::: "volatile", "intel");

    // Points to the data on the stack
    let stack_ptr = Context::save();

    if stack_ptr.int_no as u8 == transmute(Breakpoint) {
        asm!("debug:" :::: "volatile")
    }
    else {
        blue_screen(stack_ptr);
    }

    Context::restore();

    asm!("skip_exception_handler:"
        :::: "volatile", "intel");

    extern { fn exception_handler_asm(); }
    exception_handler_asm
}
<commit_msg>Remove unnecessary unsafe { } block<commit_after>use core::mem::transmute;

use core::failure;
use core::fmt;

use platform::io;
use cpu::Context;

#[repr(u8)]
pub enum Fault {
    DivideError = 0,
    NMI = 2,
    Breakpoint = 3,
    Overflow = 4,
    BoundExceeded = 5,
    InvalidOpcode = 6,
    NoMathCoprocessor = 7,
    DoubleFault = 8,
    CoprocessorSegmentOverun = 9,
    InvalidTss = 10,
    SegmentNotPresent = 11,
    StackSegmentFault = 12,
    GeneralProtection = 13,
    PageFault = 14,
    FloatingPointError = 16,
    AlignmentCheck = 17,
    MachineCheck = 18,
    SimdFpException = 19,
}

static Exceptions: &'static [&'static str] = &[
    "Divide-by-zero Error",
    "Debug",
    "Non-maskable Interrupt",
    "Breakpoint",
    "Overflow",
    "Bound Range Exceeded",
    "Invalid Opcode",
    "Device Not Available",
    "Double Fault",
    "Coprocessor Segment Overrun",
    "Invalid TSS",
    "Segment Not Present",
    "Stack-Segment Fault",
    "General Protection Fault",
    "Page Fault",
    "Reserved",
    "x87 Floating-Point Exception",
    "Alignment Check",
    "Machine Check",
    "SIMD Floating-Point Exception",
    "Virtualization Exception",
];

// TODO respect destructors
#[lang="begin_unwind"]
unsafe extern "C" fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> ! {
    asm!("hlt");
    loop { }; // for divergence check
}

#[no_split_stack]
#[inline(never)]
unsafe fn blue_screen(stack: &Context) {
    io::puts("Exception ");
    io::puts(Exceptions[stack.int_no as uint]);
    asm!("hlt");
}

#[no_split_stack]
#[inline(never)]
pub unsafe fn exception_handler() -> unsafe extern "C" fn() {
    asm!("jmp skip_exception_handler
      exception_handler_asm:"
        :::: "volatile", "intel");

    // Points to the data on the stack
    let stack_ptr = Context::save();

    if stack_ptr.int_no as u8 == transmute(Breakpoint) {
        asm!("debug:" :::: "volatile")
    }
    else {
        blue_screen(stack_ptr);
    }

    Context::restore();

    asm!("skip_exception_handler:"
        :::: "volatile", "intel");

    extern { fn exception_handler_asm(); }
    exception_handler_asm
}
<|endoftext|>


<commit_before>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
	buffer: &'a B,
	offset: usize,
	size: usize,
}

impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
	fn range(&self) -> ::std::ops::Range<usize> {
		self.offset..self.offset+self.size
	}

	fn slice(&self) -> &[u8] {
		&*self.buffer
	}
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		check_limits(memory_type.limits())?;

		if let Some(maximum_pages) = memory_type.limits().maximum() {
			if maximum_pages > LINEAR_MEMORY_MAX_PAGES {
				return Err(Error::Memory(format!("memory size must be at most 65536 pages")));
			}
		}

		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::new()), // TODO: with_capacity
			maximum_size: memory_type.limits().maximum()
				.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
				.unwrap_or(u32::MAX),
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
		}
		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let buffer = self.buffer.read();
		let region = self.checked_region(&buffer, offset as usize, size)?;

		Ok(region.slice().to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let mut buffer = self.buffer.write();
		let range = self.checked_region(&buffer, offset as usize, value.len())?.range();

		buffer[range].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
			None => Ok(u32::MAX),
			Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
			Some(new_size) => {
				buffer.extend(vec![0; (new_size - old_size) as usize]);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}

	fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
		where B: ::std::ops::Deref<Target=Vec<u8>>
	{
		let end = offset.checked_add(size)
			.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;

		if end > buffer.len() {
			return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
		}

		Ok(CheckedRegion {
			buffer: buffer,
			offset: offset,
			size: size,
		})
	}

	/// Copy memory region
	pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
		let buffer = self.buffer.write();

		let read_region = self.checked_region(&buffer, src_offset, len)?;
		let write_region = self.checked_region(&buffer, dst_offset, len)?;

		unsafe { ::std::ptr::copy(
			buffer[read_region.range()].as_ptr(),
			buffer[write_region.range()].as_ptr() as *mut _,
			len,
		)}

		Ok(())
	}
}
<commit_msg>fix range<commit_after>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
	buffer: &'a B,
	offset: usize,
	size: usize,
}

impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
	fn range(&self) -> ::std::ops::Range<usize> {
		self.offset..self.offset+self.size
	}

	fn slice(&self) -> &[u8] {
		&self.buffer[self.range()]
	}
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		check_limits(memory_type.limits())?;

		if let Some(maximum_pages) = memory_type.limits().maximum() {
			if maximum_pages > LINEAR_MEMORY_MAX_PAGES {
				return Err(Error::Memory(format!("memory size must be at most 65536 pages")));
			}
		}

		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::new()), // TODO: with_capacity
			maximum_size: memory_type.limits().maximum()
				.map(|s| s.saturating_mul(LINEAR_MEMORY_PAGE_SIZE))
				.unwrap_or(u32::MAX),
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-pages linear memory region", memory_type.limits().initial())));
		}
		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let buffer = self.buffer.read();
		let region = self.checked_region(&buffer, offset as usize, size)?;

		Ok(region.slice().to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let mut buffer = self.buffer.write();
		let range = self.checked_region(&buffer, offset as usize, value.len())?.range();

		buffer[range].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match pages.checked_mul(LINEAR_MEMORY_PAGE_SIZE).and_then(|bytes| old_size.checked_add(bytes)) {
			None => Ok(u32::MAX),
			Some(new_size) if new_size > self.maximum_size => Ok(u32::MAX),
			Some(new_size) => {
				buffer.extend(vec![0; (new_size - old_size) as usize]);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}

	fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
		where B: ::std::ops::Deref<Target=Vec<u8>>
	{
		let end = offset.checked_add(size)
			.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;

		if end > buffer.len() {
			return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
		}

		Ok(CheckedRegion {
			buffer: buffer,
			offset: offset,
			size: size,
		})
	}

	/// Copy memory region
	pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
		let buffer = self.buffer.write();

		let read_region = self.checked_region(&buffer, src_offset, len)?;
		let write_region = self.checked_region(&buffer, dst_offset, len)?;

		unsafe { ::std::ptr::copy(
			buffer[read_region.range()].as_ptr(),
			buffer[write_region.range()].as_ptr() as *mut _,
			len,
		)}

		Ok(())
	}
}
<|endoftext|>


<commit_before>// Populate a set of dummy download statistics for a specific version in the
// database.
//
// Usage:
//      cargo run --bin populate version_id1 version_id2 ...

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{db, schema::version_downloads};
use std::env;

use diesel::prelude::*;
use rand::{thread_rng, Rng};

fn main() {
    let conn = db::connect_now().unwrap();
    conn.transaction(|| update(&conn)).unwrap();
}

fn update(conn: &PgConnection) -> QueryResult<()> {
    use diesel::dsl::*;

    let ids = env::args()
        .skip(1)
        .filter_map(|arg| arg.parse::<i32>().ok());
    for id in ids {
        let mut rng = thread_rng();
        let mut dls = rng.gen_range(5_000i32, 10_000);

        for day in 0..90 {
            dls += rng.gen_range(-100, 100);

            diesel::insert_into(version_downloads::table)
                .values((
                    version_downloads::version_id.eq(id),
                    version_downloads::downloads.eq(dls),
                    version_downloads::date.eq(date(now - day.days())),
                ))
                .execute(conn)?;
        }
    }
    Ok(())
}
<commit_msg>bin/populate: Use `clap` for CLI argument parsing<commit_after>#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::{db, schema::version_downloads};

use clap::Clap;
use diesel::prelude::*;
use rand::{thread_rng, Rng};

#[derive(Clap, Debug)]
#[clap(
    name = "populate",
    about = "Populate a set of dummy download statistics for a specific version in the database."
)]
struct Opts {
    #[clap(required = true)]
    version_ids: Vec<i32>,
}

fn main() {
    let conn = db::connect_now().unwrap();
    conn.transaction(|| update(&conn)).unwrap();
}

fn update(conn: &PgConnection) -> QueryResult<()> {
    use diesel::dsl::*;

    let opts: Opts = Opts::parse();

    for id in opts.version_ids {
        let mut rng = thread_rng();
        let mut dls = rng.gen_range(5_000i32, 10_000);

        for day in 0..90 {
            dls += rng.gen_range(-100, 100);

            diesel::insert_into(version_downloads::table)
                .values((
                    version_downloads::version_id.eq(id),
                    version_downloads::downloads.eq(dls),
                    version_downloads::date.eq(date(now - day.days())),
                ))
                .execute(conn)?;
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use super::block_tokenizer::BlockTokenizer;
use super::tokens::LineType;
use super::ast::{Block, Heading, HeadingLevel};
use super::input::IntoParserInput;
use super::error::ParseError;
use std::str::Lines;

macro_rules! consume_error {
    ($tokenizer:expr) => {
        match $tokenizer.consume_raw()? {
            Err(err) => return Some(Err(err)),
            // If peek() returns an error, we know that
            // consume_raw() must return an error too.
            Ok(..) => unreachable!(),
        }
    }
}

#[derive(Debug)]
pub struct BlockParser<'a, S, I>
where
    S: IntoParserInput<'a>,
    I: Iterator<Item = S>,
{
    tokenizer: BlockTokenizer<'a, S, I>,
}

#[derive(Debug)]
pub struct TextAccumulator {
    buffer: String,
}

impl<'a> BlockParser<'a, &'a str, Lines<'a>> {
    pub fn from_string(input: &'a str) -> Self {
        BlockParser { tokenizer: BlockTokenizer::from_string(input) }
    }
}

impl<'a, S, I> BlockParser<'a, S, I>
where
    S: IntoParserInput<'a>,
    I: Iterator<Item = S>,
{
    pub fn new(input: I) -> Self {
        BlockParser { tokenizer: BlockTokenizer::new(input) }
    }

    fn parse_text(&mut self) -> Option<Result<Block, ParseError>> {
        let mut accumulator = TextAccumulator::new();

        loop {
            match self.tokenizer.peek() {
                None => break,
                Some(Err(..)) => consume_error!(self.tokenizer),
                Some(Ok(LineType::Text)) => {
                    // unwrapping here is safe
                    let line = self.tokenizer.consume(LineType::Text).unwrap().unwrap();

                    accumulator.add(&line.value().unwrap());
                }
                Some(Ok(_)) => break,
            }
        }

        Some(Ok(Block::Text { content: accumulator.consume() }))
    }

    fn parse_quote(&mut self) -> Option<Result<Block, ParseError>> {
        let mut accumulator = TextAccumulator::new();

        loop {
            match self.tokenizer.peek() {
                None => break,
                Some(Err(..)) => consume_error!(self.tokenizer),
                Some(Ok(LineType::Quote)) => {
                    // unwrapping here is safe
                    let line = self.tokenizer.consume(LineType::Quote).unwrap().unwrap();

                    accumulator.add(&line.value().unwrap());
                }
                Some(Ok(_)) => break,
            }
        }

        Some(Ok(Block::Quote { content: accumulator.consume() }))
    }

    fn parse_heading(&mut self, line_type: LineType) -> Option<Result<Block, ParseError>> {
        let level = match line_type {
            LineType::Heading1 => HeadingLevel::Level1,
            LineType::Heading2 => HeadingLevel::Level2,
            LineType::Heading3 => HeadingLevel::Level3,
            _ => return None,
        };

        match self.tokenizer.consume(line_type)? {
            Err(err) => Some(Err(err)),
            Ok(line) => Some(Ok(Block::from_inner(
                Heading::new(level, line.value()?.trim().into()),
            ))),
        }
    }
}

impl<'a, S, I> Iterator for BlockParser<'a, S, I>
where
    S: IntoParserInput<'a>,
    I: Iterator<Item = S>,
{
    type Item = Result<Block, ParseError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.tokenizer.peek()? {
                Err(..) => consume_error!(self.tokenizer),
                Ok(LineType::Blank) => {
                    self.tokenizer.consume_raw();
                    continue;
                }
                Ok(line_type) => {
                    return match line_type {
                        LineType::Text => self.parse_text(),
                        LineType::Quote => self.parse_quote(),
                        LineType::Heading1 => self.parse_heading(LineType::Heading1),
                        LineType::Heading2 => self.parse_heading(LineType::Heading2),
                        LineType::Heading3 => self.parse_heading(LineType::Heading3),
                        _ => unimplemented!(),
                    };
                }
            };
        }
    }
}

impl TextAccumulator {
    pub fn new() -> Self {
        TextAccumulator { buffer: String::new() }
    }

    ///
    /// Adds a new line to the current accumulated text.
    /// Todo: this should also take care of newlines with two spaces
    ///
    pub fn add(&mut self, line: &str) {
        if self.buffer.len() > 0 {
            self.buffer.push_str(" ");
        }

        self.buffer.push_str(line.trim());
    }

    pub fn consume(self) -> String {
        self.buffer
    }
}

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

    macro_rules! unwrap {
        ($value:expr) => {
            $value.unwrap().unwrap()
        }
    }

    #[test]
    fn it_works() {
        let mut parser = BlockParser::from_string("Lorem ipsum\ndolor sit amet");

        assert_eq!(
            Block::Text { content: "Lorem ipsum dolor sit amet".to_string() },
            unwrap!(parser.next())
        );
    }

    #[test]
    fn parsing_headings_works() {
        let mut parser = BlockParser::from_string("# hello world\n##    level 2\n### three");

        assert_eq!(
            Block::from_inner(Heading::new(HeadingLevel::Level1, "hello world".into())),
            unwrap!(parser.next())
        );

        assert_eq!(
            Block::from_inner(Heading::new(HeadingLevel::Level2, "level 2".into())),
            unwrap!(parser.next())
        );
    }

    #[test]
    fn parsing_quote_works() {
        let mut parser = BlockParser::from_string("> Foo\n> bar baz");

        assert_eq!(
            Block::Quote { content: "Foo bar baz".into() },
            unwrap!(parser.next())
        );
    }

    #[test]
    fn parsing_text_works() {
        let mut parser = BlockParser::from_string("Foo\n    \tbar baz");

        assert_eq!(
            Block::Text { content: "Foo bar baz".into() },
            unwrap!(parser.next())
        );
    }
}<commit_msg>Add tests for h3, blank lines<commit_after>use super::block_tokenizer::BlockTokenizer;
use super::tokens::LineType;
use super::ast::{Block, Heading, HeadingLevel};
use super::input::IntoParserInput;
use super::error::ParseError;
use std::str::Lines;

macro_rules! consume_error {
    ($tokenizer:expr) => {
        match $tokenizer.consume_raw()? {
            Err(err) => return Some(Err(err)),
            // If peek() returns an error, we know that
            // consume_raw() must return an error too.
            Ok(..) => unreachable!(),
        }
    }
}

#[derive(Debug)]
pub struct BlockParser<'a, S, I>
where
    S: IntoParserInput<'a>,
    I: Iterator<Item = S>,
{
    tokenizer: BlockTokenizer<'a, S, I>,
}

#[derive(Debug)]
pub struct TextAccumulator {
    buffer: String,
}

impl<'a> BlockParser<'a, &'a str, Lines<'a>> {
    pub fn from_string(input: &'a str) -> Self {
        BlockParser { tokenizer: BlockTokenizer::from_string(input) }
    }
}

impl<'a, S, I> BlockParser<'a, S, I>
where
    S: IntoParserInput<'a>,
    I: Iterator<Item = S>,
{
    pub fn new(input: I) -> Self {
        BlockParser { tokenizer: BlockTokenizer::new(input) }
    }

    fn parse_text(&mut self) -> Option<Result<Block, ParseError>> {
        let mut accumulator = TextAccumulator::new();

        loop {
            match self.tokenizer.peek() {
                None => break,
                Some(Err(..)) => consume_error!(self.tokenizer),
                Some(Ok(LineType::Text)) => {
                    // unwrapping here is safe
                    let line = self.tokenizer.consume(LineType::Text).unwrap().unwrap();

                    accumulator.add(&line.value().unwrap());
                }
                Some(Ok(_)) => break,
            }
        }

        Some(Ok(Block::Text { content: accumulator.consume() }))
    }

    fn parse_quote(&mut self) -> Option<Result<Block, ParseError>> {
        let mut accumulator = TextAccumulator::new();

        loop {
            match self.tokenizer.peek() {
                None => break,
                Some(Err(..)) => consume_error!(self.tokenizer),
                Some(Ok(LineType::Quote)) => {
                    // unwrapping here is safe
                    let line = self.tokenizer.consume(LineType::Quote).unwrap().unwrap();

                    accumulator.add(&line.value().unwrap());
                }
                Some(Ok(_)) => break,
            }
        }

        Some(Ok(Block::Quote { content: accumulator.consume() }))
    }

    fn parse_heading(&mut self, line_type: LineType) -> Option<Result<Block, ParseError>> {
        let level = match line_type {
            LineType::Heading1 => HeadingLevel::Level1,
            LineType::Heading2 => HeadingLevel::Level2,
            LineType::Heading3 => HeadingLevel::Level3,
            _ => return None,
        };

        match self.tokenizer.consume(line_type)? {
            Err(err) => Some(Err(err)),
            Ok(line) => Some(Ok(Block::from_inner(
                Heading::new(level, line.value()?.trim().into()),
            ))),
        }
    }
}

impl<'a, S, I> Iterator for BlockParser<'a, S, I>
where
    S: IntoParserInput<'a>,
    I: Iterator<Item = S>,
{
    type Item = Result<Block, ParseError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.tokenizer.peek()? {
                Err(..) => consume_error!(self.tokenizer),
                Ok(LineType::Blank) => {
                    self.tokenizer.consume_raw();
                    continue;
                }
                Ok(line_type) => {
                    return match line_type {
                        LineType::Text => self.parse_text(),
                        LineType::Quote => self.parse_quote(),
                        LineType::Heading1 => self.parse_heading(LineType::Heading1),
                        LineType::Heading2 => self.parse_heading(LineType::Heading2),
                        LineType::Heading3 => self.parse_heading(LineType::Heading3),
                        _ => unimplemented!(),
                    };
                }
            };
        }
    }
}

impl TextAccumulator {
    pub fn new() -> Self {
        TextAccumulator { buffer: String::new() }
    }

    ///
    /// Adds a new line to the current accumulated text.
    /// Todo: this should also take care of newlines with two spaces
    ///
    pub fn add(&mut self, line: &str) {
        if self.buffer.len() > 0 {
            self.buffer.push_str(" ");
        }

        self.buffer.push_str(line.trim());
    }

    pub fn consume(self) -> String {
        self.buffer
    }
}

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

    macro_rules! unwrap {
        ($value:expr) => {
            $value.unwrap().unwrap()
        }
    }

    #[test]
    fn it_works() {
        let mut parser = BlockParser::from_string("Lorem ipsum\ndolor sit amet");

        assert_eq!(
            Block::Text { content: "Lorem ipsum dolor sit amet".to_string() },
            unwrap!(parser.next())
        );
    }

    #[test]
    fn parsing_headings_works() {
        let mut parser = BlockParser::from_string("# hello world\n##    level 2\n### three");

        assert_eq!(
            Block::from_inner(Heading::new(HeadingLevel::Level1, "hello world".into())),
            unwrap!(parser.next())
        );

        assert_eq!(
            Block::from_inner(Heading::new(HeadingLevel::Level2, "level 2".into())),
            unwrap!(parser.next())
        );

        assert_eq!(
            Block::from_inner(Heading::new(HeadingLevel::Level3, "three".into())),
            unwrap!(parser.next())
        );
    }

    #[test]
    fn parsing_quote_works() {
        let mut parser = BlockParser::from_string("> Foo\n> bar baz");

        assert_eq!(
            Block::Quote { content: "Foo bar baz".into() },
            unwrap!(parser.next())
        );
    }

    #[test]
    fn parsing_text_works() {
        let mut parser = BlockParser::from_string("Foo\n    \tbar baz");

        assert_eq!(
            Block::Text { content: "Foo bar baz".into() },
            unwrap!(parser.next())
        );
    }

    #[test]
    fn blank_lines_are_ignored() {
        let mut parser = BlockParser::from_string("   \n \t \nfoo");

        assert_eq!(
            Block::Text { content: "foo".into() },
            unwrap!(parser.next())
        );
    }
}<|endoftext|>


<commit_before>use std::convert::From;

use binding::util;
use types;

use super::traits::RawObject;

pub struct Symbol {
    value: types::rb_value
}

impl Symbol {
    pub fn new(string: &str) -> Self {
        Symbol {
            value: util::id_to_sym(util::internal_id(string))
        }
    }
}

impl From<types::rb_value> for Symbol {
    fn from(value: types::rb_value) -> Self {
        Symbol {
            value: value
        }
    }
}

impl RawObject for Symbol {
    fn value(&self) -> types::rb_value {
        self.value
    }
}
<commit_msg>Implement Symbol to_string()<commit_after>use std::convert::From;

use binding::util;
use types;

use super::traits::RawObject;

pub struct Symbol {
    value: types::rb_value
}

impl Symbol {
    pub fn new(string: &str) -> Self {
        Symbol {
            value: util::id_to_sym(util::internal_id(string))
        }
    }

    pub fn to_string(&self) -> String {
        util::id_to_name(util::sym_to_id(self.value()))
    }
}

impl From<types::rb_value> for Symbol {
    fn from(value: types::rb_value) -> Self {
        Symbol {
            value: value
        }
    }
}

impl RawObject for Symbol {
    fn value(&self) -> types::rb_value {
        self.value
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chain_state::ChainState;
use libra_logger::prelude::*;
use libra_types::{
    access_path::AccessPath,
    contract_event::ContractEvent,
    language_storage::ModuleId,
    vm_error::{sub_status, StatusCode},
};
use vm::{
    errors::*,
    gas_schedule::{AbstractMemorySize, GasAlgebra, GasCarrier, GasUnits},
};
use vm_runtime_types::{
    loaded_data::struct_def::StructDef,
    values::{GlobalValue, Struct, Value},
};

/// The `InterpreterContext` context trait specifies the mutations that are allowed to the
/// `TransactionExecutionContext` within the interpreter.
pub trait InterpreterContext {
    fn move_resource_to(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
        resource: Struct,
    ) -> VMResult<()>;

    fn move_resource_from(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<Value>;

    fn resource_exists(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
    ) -> VMResult<(bool, AbstractMemorySize<GasCarrier>)>;

    fn borrow_global(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<&mut GlobalValue>;

    fn push_event(&mut self, event: ContractEvent);

    fn deduct_gas(&mut self, amount: GasUnits<GasCarrier>) -> VMResult<()>;

    fn remaining_gas(&self) -> GasUnits<GasCarrier>;

    fn exists_module(&self, m: &ModuleId) -> bool;

    fn load_module(&self, module: &ModuleId) -> VMResult<Vec<u8>>;

    fn publish_module(&mut self, module_id: ModuleId, module: Vec<u8>) -> VMResult<()>;
}

impl<T: ChainState> InterpreterContext for T {
    fn move_resource_to(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
        resource: Struct,
    ) -> VMResult<()> {
        // a resource can be written to an AccessPath if the data does not exists or
        // it was deleted (MoveFrom)
        let can_write = match self.load_data(ap, def.clone()) {
            Ok(None) => true,
            Ok(Some(_)) => false,
            Err(e) => match e.major_status {
                StatusCode::MISSING_DATA => true,
                _ => return Err(e),
            },
        };
        if can_write {
            let new_root = GlobalValue::new(Value::struct_(resource))?;
            new_root.mark_dirty()?;
            self.publish_resource(ap, (def, new_root))
        } else {
            warn!("[VM] Cannot write over existing resource {}", ap);
            Err(vm_error(
                Location::new(),
                StatusCode::CANNOT_WRITE_EXISTING_RESOURCE,
            ))
        }
    }

    fn move_resource_from(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<Value> {
        let root_ref = match self.load_data(ap, def) {
            Ok(gref) => gref,
            Err(e) => {
                warn!("[VM] (MoveFrom) Error reading data for {}: {:?}", ap, e);
                return Err(e);
            }
        };

        match root_ref.take() {
            Some((_layout, global_val)) => Ok(Value::struct_(global_val.into_owned_struct()?)),
            None => Err(
                vm_error(Location::new(), StatusCode::DYNAMIC_REFERENCE_ERROR)
                    .with_sub_status(sub_status::DRE_GLOBAL_ALREADY_BORROWED),
            ),
        }
    }

    fn resource_exists(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
    ) -> VMResult<(bool, AbstractMemorySize<GasCarrier>)> {
        Ok(match self.load_data(ap, def) {
            Ok(Some((_, gref))) => (true, gref.size()),
            Ok(None) | Err(_) => (false, AbstractMemorySize::new(0)),
        })
    }

    fn borrow_global(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<&mut GlobalValue> {
        match self.load_data(ap, def) {
            Ok(Some((_, g))) => Ok(g),
            Ok(None) => Err(
                // TODO: wrong status code?
                vm_error(Location::new(), StatusCode::DYNAMIC_REFERENCE_ERROR)
                    .with_sub_status(sub_status::DRE_GLOBAL_ALREADY_BORROWED),
            ),
            Err(e) => {
                error!("[VM] (BorrowGlobal) Error reading data for {}: {:?}", ap, e);
                Err(e)
            }
        }
    }

    fn push_event(&mut self, event: ContractEvent) {
        self.emit_event(event)
    }

    fn remaining_gas(&self) -> GasUnits<GasCarrier> {
        self.remaining_gas()
    }

    fn deduct_gas(&mut self, amount: GasUnits<GasCarrier>) -> VMResult<()> {
        self.deduct_gas(amount)
    }

    fn exists_module(&self, m: &ModuleId) -> bool {
        self.exists_module(m)
    }

    fn load_module(&self, module: &ModuleId) -> VMResult<Vec<u8>> {
        self.load_module(module)
    }

    fn publish_module(&mut self, module_id: ModuleId, module: Vec<u8>) -> VMResult<()> {
        self.publish_module(module_id, module)
    }
}
<commit_msg>[vm-runtime] make InterpreterContext::borrow_global return a shared reference<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chain_state::ChainState;
use libra_logger::prelude::*;
use libra_types::{
    access_path::AccessPath,
    contract_event::ContractEvent,
    language_storage::ModuleId,
    vm_error::{sub_status, StatusCode},
};
use vm::{
    errors::*,
    gas_schedule::{AbstractMemorySize, GasAlgebra, GasCarrier, GasUnits},
};
use vm_runtime_types::{
    loaded_data::struct_def::StructDef,
    values::{GlobalValue, Struct, Value},
};

/// The `InterpreterContext` context trait specifies the mutations that are allowed to the
/// `TransactionExecutionContext` within the interpreter.
pub trait InterpreterContext {
    fn move_resource_to(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
        resource: Struct,
    ) -> VMResult<()>;

    fn move_resource_from(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<Value>;

    fn resource_exists(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
    ) -> VMResult<(bool, AbstractMemorySize<GasCarrier>)>;

    fn borrow_global(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<&GlobalValue>;

    fn push_event(&mut self, event: ContractEvent);

    fn deduct_gas(&mut self, amount: GasUnits<GasCarrier>) -> VMResult<()>;

    fn remaining_gas(&self) -> GasUnits<GasCarrier>;

    fn exists_module(&self, m: &ModuleId) -> bool;

    fn load_module(&self, module: &ModuleId) -> VMResult<Vec<u8>>;

    fn publish_module(&mut self, module_id: ModuleId, module: Vec<u8>) -> VMResult<()>;
}

impl<T: ChainState> InterpreterContext for T {
    fn move_resource_to(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
        resource: Struct,
    ) -> VMResult<()> {
        // a resource can be written to an AccessPath if the data does not exists or
        // it was deleted (MoveFrom)
        let can_write = match self.load_data(ap, def.clone()) {
            Ok(None) => true,
            Ok(Some(_)) => false,
            Err(e) => match e.major_status {
                StatusCode::MISSING_DATA => true,
                _ => return Err(e),
            },
        };
        if can_write {
            let new_root = GlobalValue::new(Value::struct_(resource))?;
            new_root.mark_dirty()?;
            self.publish_resource(ap, (def, new_root))
        } else {
            warn!("[VM] Cannot write over existing resource {}", ap);
            Err(vm_error(
                Location::new(),
                StatusCode::CANNOT_WRITE_EXISTING_RESOURCE,
            ))
        }
    }

    fn move_resource_from(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<Value> {
        let root_ref = match self.load_data(ap, def) {
            Ok(gref) => gref,
            Err(e) => {
                warn!("[VM] (MoveFrom) Error reading data for {}: {:?}", ap, e);
                return Err(e);
            }
        };

        match root_ref.take() {
            Some((_layout, global_val)) => Ok(Value::struct_(global_val.into_owned_struct()?)),
            None => Err(
                vm_error(Location::new(), StatusCode::DYNAMIC_REFERENCE_ERROR)
                    .with_sub_status(sub_status::DRE_GLOBAL_ALREADY_BORROWED),
            ),
        }
    }

    fn resource_exists(
        &mut self,
        ap: &AccessPath,
        def: StructDef,
    ) -> VMResult<(bool, AbstractMemorySize<GasCarrier>)> {
        Ok(match self.load_data(ap, def) {
            Ok(Some((_, gref))) => (true, gref.size()),
            Ok(None) | Err(_) => (false, AbstractMemorySize::new(0)),
        })
    }

    fn borrow_global(&mut self, ap: &AccessPath, def: StructDef) -> VMResult<&GlobalValue> {
        match self.load_data(ap, def) {
            Ok(Some((_, g))) => Ok(g),
            Ok(None) => Err(
                // TODO: wrong status code?
                vm_error(Location::new(), StatusCode::DYNAMIC_REFERENCE_ERROR)
                    .with_sub_status(sub_status::DRE_GLOBAL_ALREADY_BORROWED),
            ),
            Err(e) => {
                error!("[VM] (BorrowGlobal) Error reading data for {}: {:?}", ap, e);
                Err(e)
            }
        }
    }

    fn push_event(&mut self, event: ContractEvent) {
        self.emit_event(event)
    }

    fn remaining_gas(&self) -> GasUnits<GasCarrier> {
        self.remaining_gas()
    }

    fn deduct_gas(&mut self, amount: GasUnits<GasCarrier>) -> VMResult<()> {
        self.deduct_gas(amount)
    }

    fn exists_module(&self, m: &ModuleId) -> bool {
        self.exists_module(m)
    }

    fn load_module(&self, module: &ModuleId) -> VMResult<Vec<u8>> {
        self.load_module(module)
    }

    fn publish_module(&mut self, module_id: ModuleId, module: Vec<u8>) -> VMResult<()> {
        self.publish_module(module_id, module)
    }
}
<|endoftext|>


<commit_before>use godcoin::{net_v1::PeerPool, producer::Minter, *};
use log::info;
use std::borrow::Cow;
use std::sync::Arc;

pub struct Node<'a> {
    pub bind_address: Option<&'a str>,
    pub minter_key: Option<KeyPair>,
    pub peers: Option<Vec<&'a str>>,
}

impl<'a> Node<'a> {
    pub fn start(&self) {
        use godcoin::blockchain::*;
        use std::{env, path::*};

        let home: PathBuf = {
            use dirs;
            let home = env::var("GODCOIN_HOME")
                .map(|s| PathBuf::from(s))
                .unwrap_or_else(|_| Path::join(&dirs::data_local_dir().unwrap(), "godcoin"));
            if !Path::is_dir(&home) {
                let res = std::fs::create_dir(&home);
                res.unwrap_or_else(|_| panic!("Failed to create dir at {:?}", &home));
                info!("Created GODcoin home at {:?}", &home);
            } else {
                info!("Found GODcoin home at {:?}", &home);
            }
            home
        };

        let blockchain = Blockchain::new(&home);
        info!(
            "Using height in block log at {}",
            blockchain.get_chain_height()
        );

        let blockchain = Arc::new(blockchain);
        let minter = match &self.minter_key {
            Some(key) => {
                let bond = blockchain
                    .get_bond(&key.0)
                    .expect("No bond found for minter key");
                let minter = key.clone();
                let staker = bond.staker;
                let minter = Minter::new(Arc::clone(&blockchain), minter, staker);
                Arc::new(Some(minter))
            }
            None => Arc::new(None),
        };

        {
            let peers = if let Some(peers) = &self.peers {
                Cow::Borrowed(peers)
            } else {
                Cow::Owned(vec![])
            };
            let pool = PeerPool::new(&peers);
            pool.start(&blockchain, &minter);

            // TODO synchronize blocks with peers
        }

        {
            let create_genesis = blockchain.get_block(0).is_none();
            if create_genesis && self.minter_key.is_some() {
                if let Some(ref key) = self.minter_key {
                    blockchain.create_genesis_block(key);
                }
            }
        }

        if let Some(minter) = minter.as_ref() {
            minter.clone().start_timer();
        }

        if let Some(bind) = self.bind_address {
            let addr = bind
                .parse()
                .unwrap_or_else(|_| panic!("Failed to parse address: {:?}", bind));
            net_v1::server::start(addr, blockchain, minter);
        }
    }
}
<commit_msg>Fix clippy warning<commit_after>use godcoin::{net_v1::PeerPool, producer::Minter, *};
use log::info;
use std::borrow::Cow;
use std::sync::Arc;

pub struct Node<'a> {
    pub bind_address: Option<&'a str>,
    pub minter_key: Option<KeyPair>,
    pub peers: Option<Vec<&'a str>>,
}

impl<'a> Node<'a> {
    pub fn start(&self) {
        use godcoin::blockchain::*;
        use std::{env, path::*};

        let home: PathBuf = {
            let home = {
                use dirs;
                match env::var("GODCOIN_HOME") {
                    Ok(s) => PathBuf::from(s),
                    Err(_) => Path::join(&dirs::data_local_dir().unwrap(), "godcoin"),
                }
            };
            if !Path::is_dir(&home) {
                let res = std::fs::create_dir(&home);
                res.unwrap_or_else(|_| panic!("Failed to create dir at {:?}", &home));
                info!("Created GODcoin home at {:?}", &home);
            } else {
                info!("Found GODcoin home at {:?}", &home);
            }
            home
        };

        let blockchain = Blockchain::new(&home);
        info!(
            "Using height in block log at {}",
            blockchain.get_chain_height()
        );

        let blockchain = Arc::new(blockchain);
        let minter = match &self.minter_key {
            Some(key) => {
                let bond = blockchain
                    .get_bond(&key.0)
                    .expect("No bond found for minter key");
                let minter = key.clone();
                let staker = bond.staker;
                let minter = Minter::new(Arc::clone(&blockchain), minter, staker);
                Arc::new(Some(minter))
            }
            None => Arc::new(None),
        };

        {
            let peers = if let Some(peers) = &self.peers {
                Cow::Borrowed(peers)
            } else {
                Cow::Owned(vec![])
            };
            let pool = PeerPool::new(&peers);
            pool.start(&blockchain, &minter);

            // TODO synchronize blocks with peers
        }

        {
            let create_genesis = blockchain.get_block(0).is_none();
            if create_genesis && self.minter_key.is_some() {
                if let Some(ref key) = self.minter_key {
                    blockchain.create_genesis_block(key);
                }
            }
        }

        if let Some(minter) = minter.as_ref() {
            minter.clone().start_timer();
        }

        if let Some(bind) = self.bind_address {
            let addr = bind
                .parse()
                .unwrap_or_else(|_| panic!("Failed to parse address: {:?}", bind));
            net_v1::server::start(addr, blockchain, minter);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use futures::executor::block_on;
use futures::{stream, SinkExt};
use grpcio::{Result, WriteFlags};
use kvproto::import_sstpb::*;
use tempfile::Builder;
use test_sst_importer::*;

#[allow(dead_code)]
#[path = "../../integrations/import/util.rs"]
mod util;
use self::util::{
    check_ingested_kvs, new_cluster_and_tikv_import_client, new_cluster_and_tikv_import_client_tde,
};

// Opening sst writer involves IO operation, it may block threads for a while.
// Test if download sst works when opening sst writer is blocked.
#[test]
fn test_download_sst_blocking_sst_writer() {
    let (_cluster, ctx, tikv, import) = new_cluster_and_tikv_import_client();
    let temp_dir = Builder::new()
        .prefix("test_download_sst_blocking_sst_writer")
        .tempdir()
        .unwrap();

    let sst_path = temp_dir.path().join("test.sst");
    let sst_range = (0, 100);
    let (mut meta, _) = gen_sst_file(sst_path, sst_range);
    meta.set_region_id(ctx.get_region_id());
    meta.set_region_epoch(ctx.get_region_epoch().clone());

    // Sleep 20s, make sure it is large than grpc_keepalive_timeout (3s).
    let sst_writer_open_fp = "on_open_sst_writer";
    fail::cfg(sst_writer_open_fp, "sleep(20000)").unwrap();

    // Now perform a proper download.
    let mut download = DownloadRequest::default();
    download.set_sst(meta.clone());
    download.set_storage_backend(external_storage::make_local_backend(temp_dir.path()));
    download.set_name("test.sst".to_owned());
    download.mut_sst().mut_range().set_start(vec![sst_range.1]);
    download
        .mut_sst()
        .mut_range()
        .set_end(vec![sst_range.1 + 1]);
    download.mut_sst().mut_range().set_start(Vec::new());
    download.mut_sst().mut_range().set_end(Vec::new());
    let result = import.download(&download).unwrap();
    assert!(!result.get_is_empty());
    assert_eq!(result.get_range().get_start(), &[sst_range.0]);
    assert_eq!(result.get_range().get_end(), &[sst_range.1 - 1]);

    fail::remove(sst_writer_open_fp);

    // Do an ingest and verify the result is correct.
    let mut ingest = IngestRequest::default();
    ingest.set_context(ctx.clone());
    ingest.set_sst(meta);
    let resp = import.ingest(&ingest).unwrap();
    assert!(!resp.has_error());

    check_ingested_kvs(&tikv, &ctx, sst_range);
}

fn upload_sst(import: &ImportSstClient, meta: &SstMeta, data: &[u8]) -> Result<UploadResponse> {
    let mut r1 = UploadRequest::default();
    r1.set_meta(meta.clone());
    let mut r2 = UploadRequest::default();
    r2.set_data(data.to_vec());
    let reqs: Vec<_> = vec![r1, r2]
        .into_iter()
        .map(|r| Result::Ok((r, WriteFlags::default())))
        .collect();
    let (mut tx, rx) = import.upload().unwrap();
    let mut stream = stream::iter(reqs);
    block_on(async move {
        tx.send_all(&mut stream).await?;
        tx.close().await?;
        rx.await
    })
}

#[test]
fn test_ingest_key_manager_delete_file_failed() {
    // test with tde
    let (_tmp_key_dir, _cluster, ctx, _tikv, import) = new_cluster_and_tikv_import_client_tde();

    let temp_dir = Builder::new()
        .prefix("test_download_sst_blocking_sst_writer")
        .tempdir()
        .unwrap();
    let sst_path = temp_dir.path().join("test.sst");
    let sst_range = (0, 100);
    let (mut meta, data) = gen_sst_file(sst_path, sst_range);
    meta.set_region_id(ctx.get_region_id());
    meta.set_region_epoch(ctx.get_region_epoch().clone());

    upload_sst(&import, &meta, &data).unwrap();

    let deregister_fp = "key_manager_fails_before_delete_file";
    // the first delete is in check before ingest, the second is in ingest cleanup
    // set the ingest clean up failed to trigger remove file but not remove key condition
    fail::cfg(deregister_fp, "1*off->1*return->off").unwrap();

    // Do an ingest and verify the result is correct. Though the ingest succeeded, the clone file is
    // still in the key manager
    //TODO: how to check the key manager contains the clone key
    let mut ingest = IngestRequest::default();
    ingest.set_context(ctx.clone());
    ingest.set_sst(meta.clone());
    let resp = import.ingest(&ingest).unwrap();

    assert!(!resp.has_error());

    // regenerate the file add ingest it again, even key manager contains file with the same name,
    // this action should success
    fail::remove(deregister_fp);

    // Do upload and ingest again, though key manager contians this file, the ingest action should success.
    upload_sst(&import, &meta, &data).unwrap();
    let mut ingest = IngestRequest::default();
    ingest.set_context(ctx.clone());
    ingest.set_sst(meta);
    let resp = import.ingest(&ingest).unwrap();
    assert!(!resp.has_error());
}
<commit_msg>test: fix test test_ingest_key_manager_delete_file_failed (#9150)<commit_after>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use futures::executor::block_on;
use futures::{stream, SinkExt};
use grpcio::{Result, WriteFlags};
use kvproto::import_sstpb::*;
use std::time::Duration;
use tempfile::Builder;
use test_raftstore::Simulator;
use test_sst_importer::*;
use tikv_util::HandyRwLock;

#[allow(dead_code)]
#[path = "../../integrations/import/util.rs"]
mod util;
use self::util::{
    check_ingested_kvs, new_cluster_and_tikv_import_client, new_cluster_and_tikv_import_client_tde,
};

// Opening sst writer involves IO operation, it may block threads for a while.
// Test if download sst works when opening sst writer is blocked.
#[test]
fn test_download_sst_blocking_sst_writer() {
    let (_cluster, ctx, tikv, import) = new_cluster_and_tikv_import_client();
    let temp_dir = Builder::new()
        .prefix("test_download_sst_blocking_sst_writer")
        .tempdir()
        .unwrap();

    let sst_path = temp_dir.path().join("test.sst");
    let sst_range = (0, 100);
    let (mut meta, _) = gen_sst_file(sst_path, sst_range);
    meta.set_region_id(ctx.get_region_id());
    meta.set_region_epoch(ctx.get_region_epoch().clone());

    // Sleep 20s, make sure it is large than grpc_keepalive_timeout (3s).
    let sst_writer_open_fp = "on_open_sst_writer";
    fail::cfg(sst_writer_open_fp, "sleep(20000)").unwrap();

    // Now perform a proper download.
    let mut download = DownloadRequest::default();
    download.set_sst(meta.clone());
    download.set_storage_backend(external_storage::make_local_backend(temp_dir.path()));
    download.set_name("test.sst".to_owned());
    download.mut_sst().mut_range().set_start(vec![sst_range.1]);
    download
        .mut_sst()
        .mut_range()
        .set_end(vec![sst_range.1 + 1]);
    download.mut_sst().mut_range().set_start(Vec::new());
    download.mut_sst().mut_range().set_end(Vec::new());
    let result = import.download(&download).unwrap();
    assert!(!result.get_is_empty());
    assert_eq!(result.get_range().get_start(), &[sst_range.0]);
    assert_eq!(result.get_range().get_end(), &[sst_range.1 - 1]);

    fail::remove(sst_writer_open_fp);

    // Do an ingest and verify the result is correct.
    let mut ingest = IngestRequest::default();
    ingest.set_context(ctx.clone());
    ingest.set_sst(meta);
    let resp = import.ingest(&ingest).unwrap();
    assert!(!resp.has_error());

    check_ingested_kvs(&tikv, &ctx, sst_range);
}

fn upload_sst(import: &ImportSstClient, meta: &SstMeta, data: &[u8]) -> Result<UploadResponse> {
    let mut r1 = UploadRequest::default();
    r1.set_meta(meta.clone());
    let mut r2 = UploadRequest::default();
    r2.set_data(data.to_vec());
    let reqs: Vec<_> = vec![r1, r2]
        .into_iter()
        .map(|r| Result::Ok((r, WriteFlags::default())))
        .collect();
    let (mut tx, rx) = import.upload().unwrap();
    let mut stream = stream::iter(reqs);
    block_on(async move {
        tx.send_all(&mut stream).await?;
        tx.close().await?;
        rx.await
    })
}

#[test]
fn test_ingest_key_manager_delete_file_failed() {
    // test with tde
    let (_tmp_key_dir, cluster, ctx, _tikv, import) = new_cluster_and_tikv_import_client_tde();

    let temp_dir = Builder::new()
        .prefix("test_download_sst_blocking_sst_writer")
        .tempdir()
        .unwrap();
    let sst_path = temp_dir.path().join("test.sst");
    let sst_range = (0, 100);
    let (mut meta, data) = gen_sst_file(sst_path, sst_range);
    meta.set_region_id(ctx.get_region_id());
    meta.set_region_epoch(ctx.get_region_epoch().clone());

    upload_sst(&import, &meta, &data).unwrap();

    let deregister_fp = "key_manager_fails_before_delete_file";
    // the first delete is in check before ingest, the second is in ingest cleanup
    // set the ingest clean up failed to trigger remove file but not remove key condition
    fail::cfg(deregister_fp, "1*off->1*return->off").unwrap();

    // Do an ingest and verify the result is correct. Though the ingest succeeded, the clone file is
    // still in the key manager
    //TODO: how to check the key manager contains the clone key
    let mut ingest = IngestRequest::default();
    ingest.set_context(ctx.clone());
    ingest.set_sst(meta.clone());
    let resp = import.ingest(&ingest).unwrap();

    assert!(!resp.has_error());

    fail::remove(deregister_fp);

    let node_id = *cluster.sim.rl().get_node_ids().iter().next().unwrap();
    let save_path = cluster
        .sim
        .rl()
        .importers
        .get(&node_id)
        .unwrap()
        .get_path(&meta);
    // wait up to 5 seconds to make sure raw uploaded file is deleted by the async clean up task.
    for _ in 0..50 {
        if !save_path.as_path().exists() {
            break;
        }
        std::thread::sleep(Duration::from_millis(100));
    }
    assert!(!save_path.as_path().exists());

    // Do upload and ingest again, though key manager contains this file, the ingest action should success.
    upload_sst(&import, &meta, &data).unwrap();
    let mut ingest = IngestRequest::default();
    ingest.set_context(ctx.clone());
    ingest.set_sst(meta);
    let resp = import.ingest(&ingest).unwrap();
    assert!(!resp.has_error());
}
<|endoftext|>