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

use dom::attr::Attr;
use dom::attr::AttrHelpers;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding;
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::{Document, DocumentHelpers};
use dom::element::{AttributeHandlers, HTMLTextAreaElementTypeId};
use dom::event::Event;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::keyboardevent::KeyboardEvent;
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node};
use textinput::{Multiple, TextInput, TriggerDefaultAction, DispatchInput, Nothing};
use dom::virtualmethods::VirtualMethods;

use servo_util::str::DOMString;
use string_cache::Atom;

#[dom_struct]
pub struct HTMLTextAreaElement {
    htmlelement: HTMLElement,
    textinput: DOMRefCell<TextInput>,
}

impl HTMLTextAreaElementDerived for EventTarget {
    fn is_htmltextareaelement(&self) -> bool {
        *self.type_id() == NodeTargetTypeId(ElementNodeTypeId(HTMLTextAreaElementTypeId))
    }
}

pub trait LayoutHTMLTextAreaElementHelpers {
    unsafe fn get_value_for_layout(self) -> String;
}

impl LayoutHTMLTextAreaElementHelpers for JS<HTMLTextAreaElement> {
    #[allow(unrooted_must_root)]
    unsafe fn get_value_for_layout(self) -> String {
        (*self.unsafe_get()).textinput.borrow_for_layout().get_content()
    }
}

impl HTMLTextAreaElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTextAreaElement {
        HTMLTextAreaElement {
            htmlelement: HTMLElement::new_inherited(HTMLTextAreaElementTypeId, localName, prefix, document),
            textinput: DOMRefCell::new(TextInput::new(Multiple, "".to_string())),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLTextAreaElement> {
        let element = HTMLTextAreaElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLTextAreaElementBinding::Wrap)
    }
}

impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> {
    // TODO A few of these attributes have default values and additional
    // constraints

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-cols
    make_uint_getter!(Cols)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-cols
    make_uint_setter!(SetCols, "cols")

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_getter!(Disabled)

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled")

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_getter!(Name)

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_setter!(SetName, "name")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-placeholder
    make_getter!(Placeholder)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-placeholder
    make_setter!(SetPlaceholder, "placeholder")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-required
    make_bool_getter!(Required)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-required
    make_bool_setter!(SetRequired, "required")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-rows
    make_uint_getter!(Rows)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-rows
    make_uint_setter!(SetRows, "rows")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-wrap
    make_getter!(Wrap)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-wrap
    make_setter!(SetWrap, "wrap")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-type
    fn Type(self) -> DOMString {
        "textarea".to_string()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-defaultvalue
    fn DefaultValue(self) -> DOMString {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.GetTextContent().unwrap()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-defaultvalue
    fn SetDefaultValue(self, value: DOMString) {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.SetTextContent(Some(value))
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-value
    fn Value(self) -> DOMString {
        self.textinput.borrow().get_content()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-value
    fn SetValue(self, value: DOMString) {
        self.textinput.borrow_mut().set_content(value);
    }
}

trait PrivateHTMLTextAreaElementHelpers {
    fn force_relayout(self);
}

impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
    fn force_relayout(self) {
        let doc = document_from_node(self).root();
        let node: JSRef<Node> = NodeCast::from_ref(self);
        doc.content_changed(node)
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(attr),
            _ => ()
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            },
            _ => ()
        }
    }

    fn before_remove_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(attr),
            _ => ()
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_ancestors_disabled_state_for_form_control();
            },
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.ancestors().any(|ancestor| ancestor.is_htmlfieldsetelement()) {
            node.check_ancestors_disabled_state_for_form_control();
        } else {
            node.check_disabled_attribute();
        }
    }

    fn child_inserted(&self, child: JSRef<Node>) {
        match self.super_type() {
            Some(s) => {
                s.child_inserted(child);
            }
            _ => (),
        }

        if child.is_text() {
            self.SetValue(self.DefaultValue());
        }
    }

    // copied and modified from htmlinputelement.rs
    fn handle_event(&self, event: JSRef<Event>) {
        match self.super_type() {
            Some(s) => {
                s.handle_event(event);
            }
            _ => (),
        }

        if "click" == event.Type().as_slice() && !event.DefaultPrevented() {
            //TODO: set the editing position for text inputs

            let doc = document_from_node(*self).root();
            doc.request_focus(ElementCast::from_ref(*self));
        } else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() {
                let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
                keyevent.map(|event| {
                    match self.textinput.borrow_mut().handle_keydown(event) {
                        TriggerDefaultAction => (),
                        DispatchInput => {
                            self.force_relayout();
                        }
                        Nothing => (),
                    }
                });
        }
    }
}

impl Reflectable for HTMLTextAreaElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>HTMLTextArea: Implements a dirty value flag<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::Attr;
use dom::attr::AttrHelpers;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding;
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived};
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::{Document, DocumentHelpers};
use dom::element::{AttributeHandlers, HTMLTextAreaElementTypeId};
use dom::event::Event;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::keyboardevent::KeyboardEvent;
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node};
use textinput::{Multiple, TextInput, TriggerDefaultAction, DispatchInput, Nothing};
use dom::virtualmethods::VirtualMethods;

use servo_util::str::DOMString;
use string_cache::Atom;

use std::cell::Cell;

#[dom_struct]
pub struct HTMLTextAreaElement {
    htmlelement: HTMLElement,
    textinput: DOMRefCell<TextInput>,

    // https://html.spec.whatwg.org/multipage/forms.html#concept-textarea-dirty
    value_changed: Cell<bool>,
}

impl HTMLTextAreaElementDerived for EventTarget {
    fn is_htmltextareaelement(&self) -> bool {
        *self.type_id() == NodeTargetTypeId(ElementNodeTypeId(HTMLTextAreaElementTypeId))
    }
}

pub trait LayoutHTMLTextAreaElementHelpers {
    unsafe fn get_value_for_layout(self) -> String;
}

impl LayoutHTMLTextAreaElementHelpers for JS<HTMLTextAreaElement> {
    #[allow(unrooted_must_root)]
    unsafe fn get_value_for_layout(self) -> String {
        (*self.unsafe_get()).textinput.borrow_for_layout().get_content()
    }
}

impl HTMLTextAreaElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTextAreaElement {
        HTMLTextAreaElement {
            htmlelement: HTMLElement::new_inherited(HTMLTextAreaElementTypeId, localName, prefix, document),
            textinput: DOMRefCell::new(TextInput::new(Multiple, "".to_string())),
            value_changed: Cell::new(false),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLTextAreaElement> {
        let element = HTMLTextAreaElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLTextAreaElementBinding::Wrap)
    }
}

impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> {
    // TODO A few of these attributes have default values and additional
    // constraints

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-cols
    make_uint_getter!(Cols)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-cols
    make_uint_setter!(SetCols, "cols")

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_getter!(Disabled)

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled")

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_getter!(Name)

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_setter!(SetName, "name")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-placeholder
    make_getter!(Placeholder)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-placeholder
    make_setter!(SetPlaceholder, "placeholder")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-required
    make_bool_getter!(Required)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-required
    make_bool_setter!(SetRequired, "required")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-rows
    make_uint_getter!(Rows)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-rows
    make_uint_setter!(SetRows, "rows")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-wrap
    make_getter!(Wrap)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-wrap
    make_setter!(SetWrap, "wrap")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-type
    fn Type(self) -> DOMString {
        "textarea".to_string()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-defaultvalue
    fn DefaultValue(self) -> DOMString {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.GetTextContent().unwrap()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-defaultvalue
    fn SetDefaultValue(self, value: DOMString) {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.SetTextContent(Some(value));

        // if the element's dirty value flag is false, then the element's
        // raw value must be set to the value of the element's textContent IDL attribute
        if !self.value_changed.get() {
            self.SetValue(node.GetTextContent().unwrap());
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-value
    fn Value(self) -> DOMString {
        self.textinput.borrow().get_content()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-value
    fn SetValue(self, value: DOMString) {
        self.textinput.borrow_mut().set_content(value);
        self.force_relayout();
    }
}

trait PrivateHTMLTextAreaElementHelpers {
    fn force_relayout(self);
}

impl<'a> PrivateHTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
    fn force_relayout(self) {
        let doc = document_from_node(self).root();
        let node: JSRef<Node> = NodeCast::from_ref(self);
        doc.content_changed(node)
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(attr),
            _ => ()
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            },
            _ => ()
        }
    }

    fn before_remove_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(attr),
            _ => ()
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_ancestors_disabled_state_for_form_control();
            },
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.ancestors().any(|ancestor| ancestor.is_htmlfieldsetelement()) {
            node.check_ancestors_disabled_state_for_form_control();
        } else {
            node.check_disabled_attribute();
        }
    }

    fn child_inserted(&self, child: JSRef<Node>) {
        match self.super_type() {
            Some(s) => {
                s.child_inserted(child);
            }
            _ => (),
        }

        if child.is_text() {
            self.SetValue(self.DefaultValue());
        }
    }

    // copied and modified from htmlinputelement.rs
    fn handle_event(&self, event: JSRef<Event>) {
        match self.super_type() {
            Some(s) => {
                s.handle_event(event);
            }
            _ => (),
        }

        if "click" == event.Type().as_slice() && !event.DefaultPrevented() {
            //TODO: set the editing position for text inputs

            let doc = document_from_node(*self).root();
            doc.request_focus(ElementCast::from_ref(*self));
        } else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() {
            let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
            keyevent.map(|event| {
                match self.textinput.borrow_mut().handle_keydown(event) {
                    TriggerDefaultAction => (),
                    DispatchInput => {
                        self.force_relayout();
                        self.value_changed.set(true);
                    }
                    Nothing => (),
                }
            });
        }
    }
}

impl Reflectable for HTMLTextAreaElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Safe, cross-platform-compatible wrappers for system interfaces.

mod alloc;
mod clock;
pub mod descriptor;
pub mod descriptor_reflection;
mod errno;
mod event;
pub mod external_mapping;
mod mmap;
mod notifiers;
pub mod scoped_event_macro;
mod shm;
pub mod syslog;
mod timer;
mod tube;
mod wait_context;
mod write_zeroes;

pub mod sys;
pub use sys::platform;

pub use alloc::LayoutAllocation;
pub use clock::{Clock, FakeClock};
pub use errno::{errno_result, Error, Result};
pub use event::{Event, EventReadResult, ScopedEvent};
pub use external_mapping::{Error as ExternalMappingError, Result as ExternalMappingResult, *};
pub use mmap::{MemoryMapping, MemoryMappingBuilder};
pub use notifiers::*;
pub use platform::ioctl::{
    ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val,
    *,
};
pub use scoped_event_macro::*;
pub use shm::SharedMemory;
pub use timer::{FakeTimer, Timer};
pub use tube::{Error as TubeError, RecvTube, Result as TubeResult, SendTube, Tube};
pub use wait_context::{EventToken, EventType, TriggeredEvent, WaitContext};
pub use write_zeroes::{PunchHole, WriteZeroesAt};

cfg_if::cfg_if! {
     if #[cfg(unix)] {

        pub use sys::unix;

        pub use unix::net::*;

        pub use platform::{MemoryMappingBuilderUnix, Unix as MemoryMappingUnix};
     } else if #[cfg(windows)] {
        pub use platform::MemoryMappingBuilderWindows;
        pub use platform::EventExt;
        pub use tube::{deserialize_and_recv, serialize_and_send, set_duplicate_handle_tube, set_alias_pid, DuplicateHandleTube};
     } else {
        compile_error!("Unsupported platform");
     }
}

pub use crate::descriptor::{
    AsRawDescriptor, AsRawDescriptors, Descriptor, FromRawDescriptor, IntoRawDescriptor,
    SafeDescriptor,
};
pub use log::*;
pub use platform::*;
<commit_msg>base: remove wildcard exports<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Safe, cross-platform-compatible wrappers for system interfaces.

mod alloc;
mod clock;
pub mod descriptor;
pub mod descriptor_reflection;
mod errno;
mod event;
pub mod external_mapping;
mod mmap;
mod notifiers;
pub mod scoped_event_macro;
mod shm;
pub mod syslog;
mod timer;
mod tube;
mod wait_context;
mod write_zeroes;

pub mod sys;
pub use sys::platform;

pub use alloc::LayoutAllocation;
pub use clock::{Clock, FakeClock};
pub use errno::{errno_result, Error, Result};
pub use event::{Event, EventReadResult, ScopedEvent};
pub use external_mapping::{
    Error as ExternalMappingError, ExternalMapping, Result as ExternalMappingResult,
};
pub use mmap::{MemoryMapping, MemoryMappingBuilder};
pub use notifiers::{CloseNotifier, ReadNotifier};
pub use platform::ioctl::{
    ioctl, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val,
    IoctlNr,
};
pub use shm::SharedMemory;
pub use timer::{FakeTimer, Timer};
pub use tube::{Error as TubeError, RecvTube, Result as TubeResult, SendTube, Tube};
pub use wait_context::{EventToken, EventType, TriggeredEvent, WaitContext};
pub use write_zeroes::{PunchHole, WriteZeroesAt};

cfg_if::cfg_if! {
    if #[cfg(unix)] {
        pub use sys::unix;

        pub use unix::net;

       // File related exports.
        pub use platform::{FileFlags, get_max_open_files};

        // memory/mmap related exports.
        pub use platform::{
            MemfdSeals, MemoryMappingBuilderUnix, Unix as MemoryMappingUnix,
            SharedMemoryUnix,
        };

        // descriptor/fd related exports.
        pub use platform::{
            add_fd_flags, clear_fd_flags, clone_descriptor, safe_descriptor_from_path,
            validate_raw_descriptor, clear_descriptor_cloexec,
        };

        // Event/signal related exports.
        pub use platform::{
            block_signal, clear_signal, get_blocked_signals, new_pipe_full,
            register_rt_signal_handler, signal, unblock_signal, Killable, SIGRTMIN,
            WatchingEvents, EpollContext, EpollEvents, AcpiNotifyEvent, NetlinkGenericSocket,
            SignalFd, Terminal, EventFd,
        };

        pub use platform::{
            chown, drop_capabilities, iov_max, kernel_has_memfd, pipe, read_raw_stdin
        };
        pub use platform::{enable_core_scheduling, set_rt_prio_limit, set_rt_round_robin};
        pub use platform::{flock, FlockOperation};
        pub use platform::{getegid, geteuid};
        pub use platform::{gettid, kill_process_group, reap_child};
        pub use platform::{
            net::{UnixSeqpacket, UnixSeqpacketListener, UnlinkUnixSeqpacketListener},
            ScmSocket, UnlinkUnixListener, SCM_SOCKET_MAX_FD_COUNT,
        };
    } else if #[cfg(windows)] {
        pub use platform::{EventTrigger, EventExt, WaitContextExt};
        pub use platform::MemoryMappingBuilderWindows;
        pub use platform::set_thread_priority;
        pub use platform::{give_foregrounding_permission, Console};
        pub use platform::{named_pipes, named_pipes::PipeConnection};
        pub use platform::{SafeMultimediaHandle, MAXIMUM_WAIT_OBJECTS};
        pub use crate::platform::win::{
            measure_timer_resolution, nt_query_timer_resolution, nt_set_timer_resolution,
            set_sparse_file, set_time_period,
        };
        pub use platform::ioctl::ioctl_with_ptr_sized;

        pub use tube::{
            deserialize_and_recv, serialize_and_send, set_alias_pid, set_duplicate_handle_tube,
            DuplicateHandleRequest, DuplicateHandleResponse, DuplicateHandleTube,
        };
        pub use platform::{set_audio_thread_priorities, thread};
        pub use platform::{BlockingMode, FramingMode, StreamChannel};
        pub use platform::gmtime_secure;
    } else {
        compile_error!("Unsupported platform");
    }
}

pub use platform::{
    deserialize_with_descriptors, EventContext, FileAllocate, FileGetLen, FileSerdeWrapper,
    SerializeDescriptors, UnsyncMarker,
};

pub(crate) use platform::{file_punch_hole, file_write_zeroes_at};
pub use platform::{get_cpu_affinity, set_cpu_affinity};
pub use platform::{with_as_descriptor, with_raw_descriptor, RawDescriptor, INVALID_DESCRIPTOR};
pub use platform::{PollToken, Protection};

pub use crate::descriptor::{
    AsRawDescriptor, AsRawDescriptors, Descriptor, FromRawDescriptor, IntoRawDescriptor,
    SafeDescriptor,
};

pub use platform::getpid;
pub use platform::{get_filesystem_type, open_file};
pub use platform::{pagesize, round_up_to_page_size};
pub use platform::{FileReadWriteAtVolatile, FileReadWriteVolatile, FileSetLen, FileSync};
pub use platform::{MappedRegion, MemoryMappingArena, MmapError};

pub use log::{debug, error, info, trace, warn};
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::mem::size_of;

use dora_parser::lexer::position::Position;

use crate::baseline::fct::{JitBaselineFct, JitDescriptor, JitFct, JitFctId};
use crate::baseline::map::CodeDescriptor;
use crate::cpu::{Mem, FREG_PARAMS, REG_FP, REG_PARAMS, REG_SP, REG_THREAD, REG_TMP1};
use crate::exception::DoraToNativeInfo;
use crate::gc::Address;
use crate::masm::MacroAssembler;
use crate::mem;
use crate::threads::{ThreadLocalData, THREAD};
use crate::ty::{BuiltinType, MachineMode};
use crate::vm::FctId;
use crate::vm::VM;

pub struct NativeThunks {
    map: HashMap<Address, JitFctId>,
}

impl NativeThunks {
    pub fn new() -> NativeThunks {
        NativeThunks {
            map: HashMap::new(),
        }
    }

    pub fn find_fct(&self, ptr: Address) -> Option<JitFctId> {
        self.map.get(&ptr).map(|&jit_fct_id| jit_fct_id)
    }

    pub fn insert_fct(&mut self, ptr: Address, fct: JitFctId) {
        self.map.entry(ptr).or_insert(fct);
    }
}

#[derive(Clone)]
pub enum InternalFctDescriptor {
    NativeThunk(FctId),
    AllocThunk,
    VerifyThunk,
    TrapThunk,
}

pub struct InternalFct<'a> {
    pub ptr: Address,
    pub args: &'a [BuiltinType],
    pub return_type: BuiltinType,
    pub throws: bool,
    pub desc: InternalFctDescriptor,
}

pub fn generate<'a, 'ast: 'a>(vm: &'a VM<'ast>, fct: InternalFct, dbg: bool) -> JitFctId {
    let fct_desc = fct.desc.clone();

    let ngen = NativeGen {
        vm,
        masm: MacroAssembler::new(),
        fct,
        dbg,
    };

    let jit_fct = ngen.generate();
    let jit_start = jit_fct.ptr_start();
    let jit_end = jit_fct.ptr_end();
    let jit_fct_id: JitFctId = vm.jit_fcts.push(JitFct::Base(jit_fct)).into();

    let code_desc = match fct_desc {
        InternalFctDescriptor::NativeThunk(_) => CodeDescriptor::NativeThunk(jit_fct_id),
        InternalFctDescriptor::TrapThunk => CodeDescriptor::TrapThunk,
        InternalFctDescriptor::VerifyThunk => CodeDescriptor::VerifyThunk,
        InternalFctDescriptor::AllocThunk => CodeDescriptor::AllocThunk,
    };

    vm.insert_code_map(jit_start, jit_end, code_desc);

    jit_fct_id
}

struct NativeGen<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    masm: MacroAssembler,

    fct: InternalFct<'a>,
    dbg: bool,
}

impl<'a, 'ast> NativeGen<'a, 'ast>
where
    'ast: 'a,
{
    pub fn generate(mut self) -> JitBaselineFct {
        let save_return = self.fct.return_type != BuiltinType::Unit;
        let args = self.fct.args.len();

        let dtn_size = size_of::<DoraToNativeInfo>() as i32;

        let offset_dtn = 0;
        let offset_return = dtn_size;
        let offset_args = offset_return + if save_return { mem::ptr_width() } else { 0 };
        let framesize = mem::align_i32(offset_args + args as i32 * mem::ptr_width(), 16);

        // `start_native_call` assumes that offset_dtn is on top of current stack frame.

        if self.dbg {
            self.masm.debug();
        }

        self.masm.prolog_size(framesize);

        save_params(&mut self.masm, self.fct.args, offset_args);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::fp_offset()),
            REG_FP.into(),
        );

        self.masm.copy_pc(REG_TMP1);

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::pc_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_SP.into(),
        );

        restore_params(&mut self.masm, self.fct.args, offset_args);

        self.masm.raw_call(self.fct.ptr.to_ptr());

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_TMP1.into(),
        );

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::exception_object_offset()),
        );

        let lbl_exception = self.masm.test_if_not_nil(REG_TMP1);

        self.masm.safepoint(self.vm.polling_page.addr());
        self.masm.epilog();

        self.masm.bind_label(lbl_exception);
        self.masm.throw(REG_TMP1, Position::new(1, 1));
        self.masm.nop();

        let desc = match self.fct.desc {
            InternalFctDescriptor::NativeThunk(fid) => JitDescriptor::NativeThunk(fid),
            InternalFctDescriptor::AllocThunk => JitDescriptor::AllocThunk,
            InternalFctDescriptor::VerifyThunk => JitDescriptor::VerifyThunk,
            InternalFctDescriptor::TrapThunk => JitDescriptor::TrapThunk,
        };

        self.masm.jit(self.vm, framesize, desc, self.fct.throws)
    }
}

fn save_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), freg);
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), reg);
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

fn restore_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.load_mem(mode, freg, Mem::Base(REG_SP, offset));
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.load_mem(mode, reg, Mem::Base(REG_SP, offset));
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

pub fn start_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.push_border();
    });
}

pub fn finish_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.pop_border();
    });
}
<commit_msg>dora_native: remove saven/restoring parameters<commit_after>use std::collections::hash_map::HashMap;
use std::mem::size_of;

use dora_parser::lexer::position::Position;

use crate::baseline::fct::{JitBaselineFct, JitDescriptor, JitFct, JitFctId};
use crate::baseline::map::CodeDescriptor;
use crate::cpu::{Mem, FREG_PARAMS, REG_FP, REG_PARAMS, REG_SP, REG_THREAD, REG_TMP1};
use crate::exception::DoraToNativeInfo;
use crate::gc::Address;
use crate::masm::MacroAssembler;
use crate::mem;
use crate::threads::{ThreadLocalData, THREAD};
use crate::ty::{BuiltinType, MachineMode};
use crate::vm::FctId;
use crate::vm::VM;

pub struct NativeThunks {
    map: HashMap<Address, JitFctId>,
}

impl NativeThunks {
    pub fn new() -> NativeThunks {
        NativeThunks {
            map: HashMap::new(),
        }
    }

    pub fn find_fct(&self, ptr: Address) -> Option<JitFctId> {
        self.map.get(&ptr).map(|&jit_fct_id| jit_fct_id)
    }

    pub fn insert_fct(&mut self, ptr: Address, fct: JitFctId) {
        self.map.entry(ptr).or_insert(fct);
    }
}

#[derive(Clone)]
pub enum InternalFctDescriptor {
    NativeThunk(FctId),
    AllocThunk,
    VerifyThunk,
    TrapThunk,
}

pub struct InternalFct<'a> {
    pub ptr: Address,
    pub args: &'a [BuiltinType],
    pub return_type: BuiltinType,
    pub throws: bool,
    pub desc: InternalFctDescriptor,
}

pub fn generate<'a, 'ast: 'a>(vm: &'a VM<'ast>, fct: InternalFct, dbg: bool) -> JitFctId {
    let fct_desc = fct.desc.clone();

    let ngen = NativeGen {
        vm,
        masm: MacroAssembler::new(),
        fct,
        dbg,
    };

    let jit_fct = ngen.generate();
    let jit_start = jit_fct.ptr_start();
    let jit_end = jit_fct.ptr_end();
    let jit_fct_id: JitFctId = vm.jit_fcts.push(JitFct::Base(jit_fct)).into();

    let code_desc = match fct_desc {
        InternalFctDescriptor::NativeThunk(_) => CodeDescriptor::NativeThunk(jit_fct_id),
        InternalFctDescriptor::TrapThunk => CodeDescriptor::TrapThunk,
        InternalFctDescriptor::VerifyThunk => CodeDescriptor::VerifyThunk,
        InternalFctDescriptor::AllocThunk => CodeDescriptor::AllocThunk,
    };

    vm.insert_code_map(jit_start, jit_end, code_desc);

    jit_fct_id
}

struct NativeGen<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    masm: MacroAssembler,

    fct: InternalFct<'a>,
    dbg: bool,
}

impl<'a, 'ast> NativeGen<'a, 'ast>
where
    'ast: 'a,
{
    pub fn generate(mut self) -> JitBaselineFct {
        let save_return = self.fct.return_type != BuiltinType::Unit;
        let args = self.fct.args.len();

        let dtn_size = size_of::<DoraToNativeInfo>() as i32;

        let offset_dtn = 0;
        let offset_return = dtn_size;
        let offset_args = offset_return + if save_return { mem::ptr_width() } else { 0 };
        let framesize = mem::align_i32(offset_args + args as i32 * mem::ptr_width(), 16);

        // `start_native_call` assumes that offset_dtn is on top of current stack frame.

        if self.dbg {
            self.masm.debug();
        }

        self.masm.prolog_size(framesize);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::fp_offset()),
            REG_FP.into(),
        );

        self.masm.copy_pc(REG_TMP1);

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::pc_offset()),
            REG_TMP1.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_SP.into(),
        );

        self.masm.raw_call(self.fct.ptr.to_ptr());

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_SP, offset_dtn + DoraToNativeInfo::last_offset()),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_THREAD, ThreadLocalData::dtn_offset()),
            REG_TMP1.into(),
        );

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_THREAD, ThreadLocalData::exception_object_offset()),
        );

        let lbl_exception = self.masm.test_if_not_nil(REG_TMP1);

        self.masm.safepoint(self.vm.polling_page.addr());
        self.masm.epilog();

        self.masm.bind_label(lbl_exception);
        self.masm.throw(REG_TMP1, Position::new(1, 1));
        self.masm.nop();

        let desc = match self.fct.desc {
            InternalFctDescriptor::NativeThunk(fid) => JitDescriptor::NativeThunk(fid),
            InternalFctDescriptor::AllocThunk => JitDescriptor::AllocThunk,
            InternalFctDescriptor::VerifyThunk => JitDescriptor::VerifyThunk,
            InternalFctDescriptor::TrapThunk => JitDescriptor::TrapThunk,
        };

        self.masm.jit(self.vm, framesize, desc, self.fct.throws)
    }
}

fn save_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), freg);
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.store_mem(mode, Mem::Base(REG_SP, offset), reg);
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

fn restore_params(masm: &mut MacroAssembler, args: &[BuiltinType], offset_args: i32) {
    let mut reg_idx = 0;
    let mut freg_idx = 0;
    let mut idx = 0;

    for &ty in args {
        let mode = ty.mode();
        let is_float = mode.is_float();
        let offset = offset_args + idx as i32 * 8;

        if is_float && freg_idx < FREG_PARAMS.len() {
            let freg = FREG_PARAMS[freg_idx].into();
            masm.load_mem(mode, freg, Mem::Base(REG_SP, offset));
            freg_idx += 1;
        } else if !is_float && reg_idx < REG_PARAMS.len() {
            let reg = REG_PARAMS[reg_idx].into();
            masm.load_mem(mode, reg, Mem::Base(REG_SP, offset));
            reg_idx += 1;
        } else {
            panic!("parameter saved on stack");
        }

        idx += 1;
    }
}

pub fn start_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.push_border();
    });
}

pub fn finish_native_call() {
    THREAD.with(|thread| {
        thread.borrow().handles.pop_border();
    });
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
#![cfg(all(feature = "builder", feature = "utils"))]

#[macro_use]
extern crate serde_json;
extern crate serenity;

use serde_json::Value;
use serenity::model::channel::{Embed, EmbedField, EmbedFooter, EmbedImage, EmbedVideo};
use serenity::builder::CreateEmbed;
use serenity::utils::{self, Colour};

#[test]
fn test_from_embed() {
    let embed = Embed {
        author: None,
        colour: Colour::new(0xFF0011),
        description: Some("This is a test description".to_string()),
        fields: vec![
            EmbedField {
                inline: false,
                name: "a".to_string(),
                value: "b".to_string(),
            },
            EmbedField {
                inline: true,
                name: "c".to_string(),
                value: "z".to_string(),
            },
        ],
        footer: Some(EmbedFooter {
            icon_url: Some("https://i.imgur.com/XfWpfCV.gif".to_string()),
            proxy_icon_url: None,
            text: "This is a hakase footer".to_string(),
        }),
        image: Some(EmbedImage {
            height: 213,
            proxy_url: "a".to_string(),
            url: "https://i.imgur.com/XfWpfCV.gif".to_string(),
            width: 224,
        }),
        kind: "rich".to_string(),
        provider: None,
        thumbnail: None,
        timestamp: None,
        title: Some("hakase".to_string()),
        url: Some("https://i.imgur.com/XfWpfCV.gif".to_string()),
        video: Some(EmbedVideo {
            height: 213,
            url: "https://i.imgur.com/XfWpfCV.mp4".to_string(),
            width: 224,
        }),
    };

    let builder = CreateEmbed::from(embed)
        .colour(0xFF0011)
        .description("This is a hakase description")
        .image("https://i.imgur.com/XfWpfCV.gif")
        .video("https://i.imgur.com/XfWpfCV.mp4")
        .title("still a hakase")
        .url("https://i.imgur.com/XfWpfCV.gif");

    let built = Value::Object(utils::vecmap_to_json_map(builder.0));

    let obj = json!({
        "color": 0xFF0011,
        "description": "This is a hakase description",
        "title": "still a hakase",
        "type": "rich",
        "url": "https://i.imgur.com/XfWpfCV.gif",
        "fields": [
            {
                "inline": false,
                "name": "a",
                "value": "b",
            },
            {
                "inline": true,
                "name": "c",
                "value": "z",
            },
        ],
        "image": {
            "url": "https://i.imgur.com/XfWpfCV.gif",
        },
        "video": {
            "url": "https://i.imgur.com/XfWpfCV.mp4",
        },
        "footer": {
            "text": "This is a hakase footer",
            "icon_url": "https://i.imgur.com/XfWpfCV.gif",
        }
    });

    assert_eq!(built, obj);
}
<commit_msg>Remove `CreateEmbed::video` call from reverted PR<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
#![cfg(all(feature = "builder", feature = "utils"))]

#[macro_use]
extern crate serde_json;
extern crate serenity;

use serde_json::Value;
use serenity::model::channel::{Embed, EmbedField, EmbedFooter, EmbedImage, EmbedVideo};
use serenity::builder::CreateEmbed;
use serenity::utils::{self, Colour};

#[test]
fn test_from_embed() {
    let embed = Embed {
        author: None,
        colour: Colour::new(0xFF0011),
        description: Some("This is a test description".to_string()),
        fields: vec![
            EmbedField {
                inline: false,
                name: "a".to_string(),
                value: "b".to_string(),
            },
            EmbedField {
                inline: true,
                name: "c".to_string(),
                value: "z".to_string(),
            },
        ],
        footer: Some(EmbedFooter {
            icon_url: Some("https://i.imgur.com/XfWpfCV.gif".to_string()),
            proxy_icon_url: None,
            text: "This is a hakase footer".to_string(),
        }),
        image: Some(EmbedImage {
            height: 213,
            proxy_url: "a".to_string(),
            url: "https://i.imgur.com/XfWpfCV.gif".to_string(),
            width: 224,
        }),
        kind: "rich".to_string(),
        provider: None,
        thumbnail: None,
        timestamp: None,
        title: Some("hakase".to_string()),
        url: Some("https://i.imgur.com/XfWpfCV.gif".to_string()),
        video: Some(EmbedVideo {
            height: 213,
            url: "https://i.imgur.com/XfWpfCV.mp4".to_string(),
            width: 224,
        }),
    };

    let builder = CreateEmbed::from(embed)
        .colour(0xFF0011)
        .description("This is a hakase description")
        .image("https://i.imgur.com/XfWpfCV.gif")
        .title("still a hakase")
        .url("https://i.imgur.com/XfWpfCV.gif");

    let built = Value::Object(utils::vecmap_to_json_map(builder.0));

    let obj = json!({
        "color": 0xFF0011,
        "description": "This is a hakase description",
        "title": "still a hakase",
        "type": "rich",
        "url": "https://i.imgur.com/XfWpfCV.gif",
        "fields": [
            {
                "inline": false,
                "name": "a",
                "value": "b",
            },
            {
                "inline": true,
                "name": "c",
                "value": "z",
            },
        ],
        "image": {
            "url": "https://i.imgur.com/XfWpfCV.gif",
        },
        "video": {
            "url": "https://i.imgur.com/XfWpfCV.mp4",
        },
        "footer": {
            "text": "This is a hakase footer",
            "icon_url": "https://i.imgur.com/XfWpfCV.gif",
        }
    });

    assert_eq!(built, obj);
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[macro_use]
extern crate log;
extern crate uuid;
extern crate devicemapper;
extern crate libstratis;
extern crate rand;
extern crate tempdir;
#[macro_use]
mod util;

use devicemapper::DM;

use libstratis::engine::strat_engine::blockdev;
use libstratis::engine::strat_engine::blockdev::BlockDev;
use libstratis::engine::strat_engine::lineardev::LinearDev;
use libstratis::engine::strat_engine::metadata::MIN_MDA_SECTORS;
use libstratis::engine::strat_engine::thindev::ThinDev;
use libstratis::engine::strat_engine::thinpooldev::ThinPoolDev;
use libstratis::types::DataBlocks;
use libstratis::types::Sectors;

use std::path::Path;

use tempdir::TempDir;

use util::blockdev_utils::clean_blockdev_headers;
use util::blockdev_utils::wipe_header;
use util::blockdev_utils::write_files_to_directory;
use util::test_config::TestConfig;
use util::test_consts::DEFAULT_CONFIG_FILE;
use util::test_result::TestResult;

use uuid::Uuid;

fn setup_supporting_devs(dm: &DM,
                         metadata_blockdev: &BlockDev,
                         data_blockdev: &BlockDev)
                         -> TestResult<(LinearDev, LinearDev)> {

    let meta_blockdevs = vec![metadata_blockdev];
    let metadata_dev =
        try!(LinearDev::new("stratis_testing_thinpool_metadata", dm, &meta_blockdevs));

    let data_blockdevs = vec![data_blockdev];
    let data_dev = try!(LinearDev::new("stratis_testing_thinpool_datadev", dm, &data_blockdevs));

    let metadata_path = try!(metadata_dev.path());
    let data_path = try!(data_dev.path());
    try!(wipe_header(Path::new(&metadata_path)));
    try!(wipe_header(Path::new(&data_path)));

    Ok((metadata_dev, data_dev))
}

/// Validate the blockdev_paths are unique
/// Initialize the list for use with Stratis
/// Create a thin-pool via ThinPoolDev
/// Validate the resulting thin-pool dev and meta dev
fn test_thinpool_setup(dm: &DM, blockdev_paths: &Vec<&Path>) -> TestResult<ThinPoolDev> {

    let uuid = Uuid::new_v4();

    let unique_blockdevs = blockdev::resolve_devices(blockdev_paths).unwrap();

    let blockdev_map = blockdev::initialize(&uuid, unique_blockdevs, MIN_MDA_SECTORS, true)
        .unwrap();

    let (_first_key, metadata_blockdev) = blockdev_map.iter().next().unwrap();
    let (_last_key, data_blockdev) = blockdev_map.iter().next_back().unwrap();
    let (_start_sector, length) = data_blockdev.avail_range();

    let (metadata_dev, data_dev) =
        try!(setup_supporting_devs(dm, metadata_blockdev, data_blockdev));

    let mut thinpool_dev = try!(ThinPoolDev::new("stratis_testing_thinpool",
                                                 dm,
                                                 length,
                                                 Sectors(1024),
                                                 DataBlocks(256000),
                                                 metadata_dev,
                                                 data_dev));

    try!(test_thindev_setup(&dm, &mut thinpool_dev));

    Ok(thinpool_dev)
}

fn test_thindev_setup(dm: &DM, thinpool_dev: &mut ThinPoolDev) -> TestResult<()> {
    let thin_id = rand::random::<u16>();
    let mut thin_dev = try!(ThinDev::new("stratis_testing_thindev",
                                         &dm,
                                         thinpool_dev,
                                         thin_id as u32,
                                         Sectors(300000)));

    let tmp_dir = try!(TempDir::new("stratis_testing"));

    try!(thin_dev.create_fs());
    try!(thin_dev.mount_fs(tmp_dir.path()));
    try!(write_files_to_directory(&tmp_dir, 100));

    try!(thin_dev.unmount_fs(tmp_dir.path()));
    try!(thin_dev.teardown(dm));
    Ok(())
}

#[test]
/// Get list of safe to destroy devices.
/// Clean any headers from the devices.
/// Construct meta and data devices for use in the thin-pool
/// Test creating a thin-pool device
/// Test create a thin device provisioned from the pool
/// Teardown the DM devices in the proper order
pub fn test_thinpool() {

    let dm = DM::new().unwrap();

    let mut test_config = TestConfig::new(DEFAULT_CONFIG_FILE);
    let _ = test_config.init();

    let safe_to_destroy_devs = match test_config.get_safe_to_destroy_devs() {
        Ok(devs) => {
            if devs.len() < 2 {
                warn!("test_thinpool requires at least 2 devices to run.  Test not \
                       run.");
                return;
            }
            devs
        }
        Err(e) => {
            error!("Failed : get_safe_to_destroy_devs : {:?}", e);
            return;
        }
    };

    info!("safe_to_destroy_devs = {:?}", safe_to_destroy_devs);
    let device_paths = safe_to_destroy_devs.iter().map(|x| Path::new(x)).collect::<Vec<&Path>>();

    assert_ok!(clean_blockdev_headers(&device_paths));
    info!("devices cleaned for test");

    let mut thinpool_dev = assert_ok!(test_thinpool_setup(&dm, &device_paths));

    thinpool_dev.teardown(&dm).unwrap();
}
<commit_msg>Update a test<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[macro_use]
extern crate log;
extern crate uuid;
extern crate devicemapper;
extern crate libstratis;
extern crate rand;
extern crate tempdir;
#[macro_use]
mod util;

use devicemapper::DM;

use libstratis::engine::strat_engine::blockdev;
use libstratis::engine::strat_engine::blockdev::BlockDev;
use libstratis::engine::strat_engine::lineardev::LinearDev;
use libstratis::engine::strat_engine::metadata::MIN_MDA_SECTORS;
use libstratis::engine::strat_engine::thindev::ThinDev;
use libstratis::engine::strat_engine::thinpooldev::ThinPoolDev;
use libstratis::types::DataBlocks;
use libstratis::types::Sectors;

use std::path::Path;

use tempdir::TempDir;

use util::blockdev_utils::clean_blockdev_headers;
use util::blockdev_utils::wipe_header;
use util::blockdev_utils::write_files_to_directory;
use util::test_config::TestConfig;
use util::test_consts::DEFAULT_CONFIG_FILE;
use util::test_result::TestResult;

use uuid::Uuid;

fn setup_supporting_devs(dm: &DM,
                         metadata_blockdev: &BlockDev,
                         data_blockdev: &BlockDev)
                         -> TestResult<(LinearDev, LinearDev)> {

    let meta_blockdevs = vec![metadata_blockdev];
    let metadata_dev =
        try!(LinearDev::new("stratis_testing_thinpool_metadata", dm, &meta_blockdevs));

    let data_blockdevs = vec![data_blockdev];
    let data_dev = try!(LinearDev::new("stratis_testing_thinpool_datadev", dm, &data_blockdevs));

    let metadata_path = try!(metadata_dev.path());
    let data_path = try!(data_dev.path());
    try!(wipe_header(Path::new(&metadata_path)));
    try!(wipe_header(Path::new(&data_path)));

    Ok((metadata_dev, data_dev))
}

/// Validate the blockdev_paths are unique
/// Initialize the list for use with Stratis
/// Create a thin-pool via ThinPoolDev
/// Validate the resulting thin-pool dev and meta dev
fn test_thinpool_setup(dm: &DM, blockdev_paths: &Vec<&Path>) -> TestResult<ThinPoolDev> {

    let uuid = Uuid::new_v4();

    let unique_blockdevs = blockdev::resolve_devices(blockdev_paths).unwrap();

    let blockdev_map = blockdev::initialize(&uuid, unique_blockdevs, MIN_MDA_SECTORS, true)
        .unwrap();

    let (_first_key, metadata_blockdev) = blockdev_map.iter().next().unwrap();
    let (_last_key, data_blockdev) = blockdev_map.iter().next_back().unwrap();
    let (_start_sector, length) = data_blockdev.avail_range();

    let (metadata_dev, data_dev) =
        try!(setup_supporting_devs(dm, metadata_blockdev, data_blockdev));

    let mut thinpool_dev = try!(ThinPoolDev::new("stratis_testing_thinpool",
                                                 dm,
                                                 length,
                                                 Sectors(1024),
                                                 DataBlocks(256000),
                                                 metadata_dev,
                                                 data_dev));

    try!(test_thindev_setup(&dm, &mut thinpool_dev));

    Ok(thinpool_dev)
}

fn test_thindev_setup(dm: &DM, thinpool_dev: &mut ThinPoolDev) -> TestResult<()> {
    let thin_id = rand::random::<u16>();
    let mut thin_dev = try!(ThinDev::new("stratis_testing_thindev",
                                         &dm,
                                         thinpool_dev,
                                         thin_id as u32,
                                         Sectors(300000)));

    let tmp_dir = try!(TempDir::new("stratis_testing"));

    try!(thin_dev.create_fs());
    try!(thin_dev.mount_fs(tmp_dir.path()));
    try!(write_files_to_directory(&tmp_dir, 100));

    try!(thin_dev.unmount_fs(tmp_dir.path()));
    try!(thin_dev.teardown(dm));
    Ok(())
}

#[test]
/// Get list of safe to destroy devices.
/// Clean any headers from the devices.
/// Construct meta and data devices for use in the thin-pool
/// Test creating a thin-pool device
/// Test create a thin device provisioned from the pool
/// Teardown the DM devices in the proper order
pub fn test_thinpool() {

    let dm = DM::new().unwrap();

    let mut test_config = TestConfig::new(DEFAULT_CONFIG_FILE);
    let _ = test_config.init();

    let safe_to_destroy_devs = match test_config.get_safe_to_destroy_devs() {
        Ok(devs) => {
            if devs.len() < 2 {
                warn!("test_thinpool requires at least 2 devices to run.  Test not \
                       run.");
                return;
            }
            devs
        }
        Err(e) => {
            error!("Failed : get_safe_to_destroy_devs : {:?}", e);
            return;
        }
    };

    info!("safe_to_destroy_devs = {:?}", safe_to_destroy_devs);
    let device_paths = safe_to_destroy_devs.iter().map(|x| Path::new(x)).collect::<Vec<&Path>>();

    assert_ok!(clean_blockdev_headers(&device_paths));
    info!("devices cleaned for test");

    let thinpool_dev = assert_ok!(test_thinpool_setup(&dm, &device_paths));

    thinpool_dev.teardown(&dm).unwrap();
}
<|endoftext|>


<commit_before>use std::rand;

static NTASKS: uint = 20;

fn sum_first_then_divide(slice: &[uint]) -> f32 {
    let len = slice.len();
    let mut sum = 0u;
    for i in range(0u, len) {
        sum += slice[i];
    }
    let fsum = sum as f32;
    let flen = len as f32;
    fsum / flen
}

fn recursive_sum(slice: &[uint]) -> f32 {
    let len = slice.len();
    let mut sum;
    match len {
        0u => {
            sum = 0.0f32;
        },
        1u => {
            sum = slice[0] as f32;
        },
        2u => {
            sum = (slice[0] + slice[1]) as f32 / 2.0f32;
        },
        _ => {
            let lm1 = (len - 1) as f32;
            let flen = len as f32;
            let f1 = lm1 / flen;
            let f2 = 1.0f32 / flen;
            let slm1 = slice[len-1] as f32;
            sum = f1 * recursive_sum(slice.slice(0, len-1)) + f2 * slm1;
        },
    };
    sum
}

fn do_sequential(id: uint) {
    // create array (filled with zeros)
    let mut a = [0u, ..7000u];
    for i in range(1u, 10_001) {
        // fill array (randomly) with values in [0,99]
        for i in range(0u, 7000u) {
            a[i] = rand::random::<uint>() % 1000u;
        }
        let b = a; // non-mutable copy
        // sum1
        let sum1 = sum_first_then_divide(b);
        // sum2
        let sum2 = recursive_sum(b);
        if i % 1000u == 0u {
            println!("({}, {}): sum1 = {}", id, i, sum1);
            println!("({}, {}): sum2 = {}", id, i, sum2);
        }
    }
}

fn do_in_parallel() {
    for p in range(0u, NTASKS) {
        spawn(proc() {
            do_sequential(p);
        });
    }
}

fn main() {
    println!("do_sequential()");
    do_sequential(0);
    println!("do_in_parallel()");
    do_in_parallel();
}
<commit_msg>Reduce tasks to 8 and add a third method to sum and divide.<commit_after>use std::rand;

static NTASKS: uint = 8;

fn sum_first_then_divide(slice: &[uint]) -> f32 {
    let len = slice.len();
    let mut sum = 0u;
    for i in range(0u, len) {
        sum += slice[i];
    }
    let fsum = sum as f32;
    let flen = len as f32;
    fsum / flen
}

fn divide_while_summing_up(slice: &[uint]) -> f32 {
    let len = slice.len();
    let flen = len as f32;
    let mut sum = 0f32;
    for i in range(0u, len) {
        sum += (slice[i] as f32) / flen;
    }
    sum
}

fn recursive_sum(slice: &[uint]) -> f32 {
    let len = slice.len();
    let mut sum;
    match len {
        0u => {
            sum = 0.0f32;
        },
        1u => {
            sum = slice[0] as f32;
        },
        2u => {
            sum = (slice[0] + slice[1]) as f32 / 2.0f32;
        },
        _ => {
            let lm1 = (len - 1) as f32;
            let flen = len as f32;
            let f1 = lm1 / flen;
            let f2 = 1.0f32 / flen;
            let slm1 = slice[len-1] as f32;
            sum = f1 * recursive_sum(slice.slice(0, len-1)) + f2 * slm1;
        },
    };
    sum
}

fn do_sequential(id: uint) {
    // create array (filled with zeros)
    let mut a = [0u, ..7000u];
    for i in range(1u, 10_001) {
        // fill array (randomly) with values in [0,99]
        for i in range(0u, 7000u) {
            a[i] = rand::random::<uint>() % 1000u;
        }
        let b = a; // non-mutable copy
        // sum1
        let sum1 = sum_first_then_divide(b);
        // sum2
        let sum2 = divide_while_summing_up(b);
        // sum3
        let sum3 = recursive_sum(b);
        if i % 1000u == 0u {
            println!("({}, {}): sum1 = {}", id, i, sum1);
            println!("({}, {}): sum2 = {}", id, i, sum2);
            println!("({}, {}): sum3 = {}", id, i, sum3);
        }
    }
}

fn do_in_parallel() {
    for p in range(0u, NTASKS) {
        spawn(proc() {
            do_sequential(p);
        });
    }
}

fn main() {
    println!("do_sequential()");
    do_sequential(0);
    println!("do_in_parallel()");
    do_in_parallel();
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<commit_msg>submission: create metadata types<commit_after>extern crate serde;

use super::content::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
pub struct FieldId(pub String);

#[derive(Serialize, Deserialize, Clone)]
pub struct Field {
    pub id: FieldId,
    pub title: Text,
    pub types: Vec<FileType>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct FileTypeId(pub String);

#[derive(Serialize, Deserialize, Clone)]
pub struct FileTypeExtension(pub String);

#[derive(Serialize, Deserialize, Clone)]
pub struct FileType {
    pub id: FileTypeId,
    pub title: Text,
    pub extensions: Vec<FileTypeExtension>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Form {
    pub fields: Vec<Field>,
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<|endoftext|>


<commit_before>use common::types::{
	Ty,
	bool_ty
};

use util::boxed::{
	ToBoxedVec,
};

#[derive(Clone)]
pub struct Expr (pub Ty, pub ExprKind);

impl Expr
{
	#[inline]
	pub fn ty(&self) -> &Ty
	{
		&self.0
	}

	#[inline]
	pub fn kind(&self) -> &ExprKind
	{
		&self.1
	}
}

/// Expression Specific Element
#[derive(Clone)]
pub enum ExprKind {
  // Unary Expressions
  Not      (Box<Expr>),
  IsNull   (Box<Expr>),
  IsNotNull(Box<Expr>),
  PlusSign (Box<Expr>),
  MinusSign(Box<Expr>),
  Cast     (Box<Expr>, Ty, Ty),

  // Binary Arithmetic Expressions
  And(Box<Expr>,Box<Expr>),
  Or(Box<Expr>,Box<Expr>),
  Cmp(CmpOp, Box<Expr>, Box<Expr>),
  Arithm(ArithmOp, Box<Expr>, Box<Expr>),

  // function and values
  Fn(FnDecl, Vec<Box<Expr>>),
  Field(String),
  Const(Literal),

  // condition
  Switch(Vec<Box<Expr>>, Box<Expr>), // multiple conditions, else return value
  Case  (Box<Expr>, Box<Expr>),      // condition, return value
}

/// Comparison Operator Type
#[derive(Clone, Copy)]
pub enum CmpOp {
  Eq,
  Ne,
  Lt,
  Le,
  Gt,
  Ge
}

/// Arithmetic Operator Type
#[derive(Clone, Copy)]
pub enum ArithmOp {
  Plus,
  Sub,
  Mul,
  Div,
  Rem,
}

/// Function Declaration
#[derive(Clone)]
pub struct FnDecl {
  signature: String,
  ret_ty: Ty
}

impl FnDecl
{
	pub fn ty(&self) -> &Ty
	{
		&self.ret_ty
	}
}

/// Representation for a single value
#[derive(Clone)]
pub enum Literal
{
  Bool(bool),
  I8(i8),
  I16(i16),
  I32(i32),
  I64(i64),
  F32(f32),
  F64(f64),
  String(String)
}

macro_rules! into_literal(
	($ty:ty, $literal_kind:ident) => (
    impl Into<Literal> for $ty {
	    fn into(self) -> Literal
	    {
	    	Literal::$literal_kind(self)
	    }
    }
  );
);

into_literal!(bool, Bool);
into_literal!(i8,   I8);
into_literal!(i16,  I16);
into_literal!(i32,  I32);
into_literal!(i64,  I64);
into_literal!(f32,  F32);
into_literal!(f64,  F64);

#[allow(non_snake_case)]
pub fn Not(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::Not(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNotNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn Cast(c: Expr, from_ty: &Ty, to_ty: &Ty) -> Expr
{
	Expr(to_ty.clone(), ExprKind::Cast(Box::new(c), from_ty.clone(), to_ty.clone()))
}

#[allow(non_snake_case)]
pub fn PlusSign(c: Expr) -> Expr
{
	Expr(c.ty().	clone(), ExprKind::PlusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn MinusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::MinusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn And(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::And(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Or(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Or(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Cmp(op: CmpOp, l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Cmp(op, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Arithm(op: &ArithmOp, ret_type: &Ty, l: Expr, r: Expr) -> Expr
{
	Expr(ret_type.clone(), ExprKind::Arithm(*op, Box::new(l), Box::new(r)))
}

pub fn Subtract(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Sub, Box::new(l), Box::new(r)))
}

pub fn Mul(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Mul, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Func(decl: FnDecl, args: Vec<Expr>) -> Expr
{
	Expr(decl.ty().clone(), ExprKind::Fn(decl, args.to_boxed()))
}

#[allow(non_snake_case)]
pub fn Switch(cases: Vec<Expr>, default: Expr) -> Expr
{
	Expr(default.ty().clone(), ExprKind::Switch(cases.to_boxed(), Box::new(default)))
}

#[allow(non_snake_case)]
pub fn Case(cond: Expr, result: Expr) -> Expr
{
	Expr(result.ty().clone(), ExprKind::Case(Box::new(cond), Box::new(result)))
}

#[allow(non_snake_case)]
pub fn Const<T: Into<Literal>>(value: T) -> Expr
{
	let literal = value.into();
	let ty = match literal {
		Literal::Bool(_) => bool_ty(),
		_                => panic!("unsupported type")
	};

	Expr(ty, ExprKind::Const(literal))
}

#[allow(non_snake_case)]
pub fn Field(name: String, ty: Ty) -> Expr
{
	Expr(ty, ExprKind::Field(name))
}

pub fn clone(e: &Box<Expr>) -> Expr
{
	*(e.clone())
}

pub mod optimizer
{
	pub use expr_optimizer::*;
}

pub mod visitor
{
	//! Visitor for Expr
	use super::*;

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait Visitor: Sized
	{
	  fn accept(&mut self, e: &Expr)
	  {
	    accept_by_default(self, e);
	  }
	}

	pub fn accept_by_default<T>(v: &mut T, e: &Expr) where T: Visitor + Sized {
	  match *e.kind() {
	    ExprKind::Not      (ref c)       => v.accept(c),
	    ExprKind::IsNull   (ref c)       => v.accept(c),
	    ExprKind::IsNotNull(ref c)       => v.accept(c),
	    ExprKind::PlusSign (ref c)       => v.accept(c),
	    ExprKind::MinusSign(ref c)       => v.accept(c),
	    ExprKind::Cast     (ref c, _, _) => v.accept(c),

	    ExprKind::And      (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Or       (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Cmp      (_, ref l, ref r) => { v.accept(l); v.accept(r) },
	    ExprKind::Arithm   (_, ref l, ref r) => { v.accept(l); v.accept(r) },

	    ExprKind::Fn     (_, ref args)  => { for e in args.iter() { v.accept(e) } },
			ExprKind::Field  (_) 	          => {},
	    ExprKind::Const  (_)            => {}

	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },
	  }
	}

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait TransformVisitor: Sized
  {
	  fn transform(&self, e: &Expr) -> Expr
	  {
	    transform_by_default(self, e)
	  }
	}

	pub fn transform_by_default<T>(v: &T, e: &Expr) -> Expr
			where T: TransformVisitor + Sized
	{
		match *e.kind() {
	    ExprKind::Not      (ref c)               => Not      (v.transform(c)),
	    ExprKind::IsNull   (ref c)               => IsNull   (v.transform(c)),
	    ExprKind::IsNotNull(ref c)               => IsNotNull(v.transform(c)),
	    ExprKind::PlusSign (ref c)               => PlusSign (v.transform(c)),
	    ExprKind::MinusSign(ref c)               => MinusSign(v.transform(c)),
	    ExprKind::Cast     (ref c, ref f, ref t) => Cast     (v.transform(c), f, t),

	    ExprKind::And      (ref l, ref r)        => And(v.transform(l), v.transform(r)),
	    ExprKind::Or       (ref l, ref r)        => Or (v.transform(l), v.transform(r)),
	    ExprKind::Cmp      (ref o, ref l, ref r) => Cmp(*o, v.transform(l), v.transform(r)),
	    ExprKind::Arithm   (ref o, ref l, ref r) => Arithm(o, e.ty(), v.transform(l), v.transform(r)),

	    ExprKind::Fn       (ref f, ref args)     => {
	    	let rargs = args.iter().map(|arg| v.transform(arg)).collect::<Vec<Expr>>();
	    	Func(f.clone(), rargs)
    	},
			ExprKind::Field     (_) 	                => e.clone(),
	    ExprKind::Const     (_)                   => e.clone(),

	    ExprKind::Switch   (ref cases, ref default)  => {
	    	let rcases = cases.iter().map(|case| v.transform(case)).collect::<Vec<Expr>>();

	    	Switch(rcases, v.transform(default))
   	  }
	    ExprKind::Case      (ref l, ref r)        => Case(v.transform(l), v.transform(r)),
	  }
	}
}<commit_msg>Refactor the signature of Field function.<commit_after>use common::types::{
	Ty,
	bool_ty
};

use util::boxed::{
	ToBoxedVec,
};

#[derive(Clone)]
pub struct Expr (pub Ty, pub ExprKind);

impl Expr
{
	#[inline]
	pub fn ty(&self) -> &Ty
	{
		&self.0
	}

	#[inline]
	pub fn kind(&self) -> &ExprKind
	{
		&self.1
	}
}

/// Expression Specific Element
#[derive(Clone)]
pub enum ExprKind {
  // Unary Expressions
  Not      (Box<Expr>),
  IsNull   (Box<Expr>),
  IsNotNull(Box<Expr>),
  PlusSign (Box<Expr>),
  MinusSign(Box<Expr>),
  Cast     (Box<Expr>, Ty, Ty),

  // Binary Arithmetic Expressions
  And(Box<Expr>,Box<Expr>),
  Or(Box<Expr>,Box<Expr>),
  Cmp(CmpOp, Box<Expr>, Box<Expr>),
  Arithm(ArithmOp, Box<Expr>, Box<Expr>),

  // function and values
  Fn(FnDecl, Vec<Box<Expr>>),
  Field(String),
  Const(Literal),

  // condition
  Switch(Vec<Box<Expr>>, Box<Expr>), // multiple conditions, else return value
  Case  (Box<Expr>, Box<Expr>),      // condition, return value
}

/// Comparison Operator Type
#[derive(Clone, Copy)]
pub enum CmpOp {
  Eq,
  Ne,
  Lt,
  Le,
  Gt,
  Ge
}

/// Arithmetic Operator Type
#[derive(Clone, Copy)]
pub enum ArithmOp {
  Plus,
  Sub,
  Mul,
  Div,
  Rem,
}

/// Function Declaration
#[derive(Clone)]
pub struct FnDecl {
  signature: String,
  ret_ty: Ty
}

impl FnDecl
{
	pub fn ty(&self) -> &Ty
	{
		&self.ret_ty
	}
}

/// Representation for a single value
#[derive(Clone)]
pub enum Literal
{
  Bool(bool),
  I8(i8),
  I16(i16),
  I32(i32),
  I64(i64),
  F32(f32),
  F64(f64),
  String(String)
}

macro_rules! into_literal(
	($ty:ty, $literal_kind:ident) => (
    impl Into<Literal> for $ty {
	    fn into(self) -> Literal
	    {
	    	Literal::$literal_kind(self)
	    }
    }
  );
);

into_literal!(bool, Bool);
into_literal!(i8,   I8);
into_literal!(i16,  I16);
into_literal!(i32,  I32);
into_literal!(i64,  I64);
into_literal!(f32,  F32);
into_literal!(f64,  F64);

#[allow(non_snake_case)]
pub fn Not(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::Not(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNotNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn Cast(c: Expr, from_ty: &Ty, to_ty: &Ty) -> Expr
{
	Expr(to_ty.clone(), ExprKind::Cast(Box::new(c), from_ty.clone(), to_ty.clone()))
}

#[allow(non_snake_case)]
pub fn PlusSign(c: Expr) -> Expr
{
	Expr(c.ty().	clone(), ExprKind::PlusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn MinusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::MinusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn And(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::And(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Or(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Or(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Cmp(op: CmpOp, l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Cmp(op, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Arithm(op: &ArithmOp, ret_type: &Ty, l: Expr, r: Expr) -> Expr
{
	Expr(ret_type.clone(), ExprKind::Arithm(*op, Box::new(l), Box::new(r)))
}

#[warn(non_snake_case)]
pub fn Plus(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Plus, Box::new(l), Box::new(r)))
}

#[warn(non_snake_case)]
pub fn Subtract(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Sub, Box::new(l), Box::new(r)))
}

#[warn(non_snake_case)]
pub fn Mul(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Mul, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Func(decl: FnDecl, args: Vec<Expr>) -> Expr
{
	Expr(decl.ty().clone(), ExprKind::Fn(decl, args.to_boxed()))
}

#[allow(non_snake_case)]
pub fn Switch(cases: Vec<Expr>, default: Expr) -> Expr
{
	Expr(default.ty().clone(), ExprKind::Switch(cases.to_boxed(), Box::new(default)))
}

#[allow(non_snake_case)]
pub fn Case(cond: Expr, result: Expr) -> Expr
{
	Expr(result.ty().clone(), ExprKind::Case(Box::new(cond), Box::new(result)))
}

#[allow(non_snake_case)]
pub fn Const<T: Into<Literal>>(value: T) -> Expr
{
	let literal = value.into();
	let ty = match literal {
		Literal::Bool(_) => bool_ty(),
		_                => panic!("unsupported type")
	};

	Expr(ty, ExprKind::Const(literal))
}

#[allow(non_snake_case)]
pub fn Field(ty: &Ty, name: &str) -> Expr
{
	Expr(ty.clone(), ExprKind::Field(name.to_string()))
}

pub fn clone(e: &Box<Expr>) -> Expr
{
	*(e.clone())
}

pub mod optimizer
{
	pub use expr_optimizer::*;
}

pub mod visitor
{
	//! Visitor for Expr
	use super::*;

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait Visitor: Sized
	{
	  fn accept(&mut self, e: &Expr)
	  {
	    accept_by_default(self, e);
	  }
	}

	pub fn accept_by_default<T>(v: &mut T, e: &Expr) where T: Visitor + Sized {
	  match *e.kind() {
	    ExprKind::Not      (ref c)       => v.accept(c),
	    ExprKind::IsNull   (ref c)       => v.accept(c),
	    ExprKind::IsNotNull(ref c)       => v.accept(c),
	    ExprKind::PlusSign (ref c)       => v.accept(c),
	    ExprKind::MinusSign(ref c)       => v.accept(c),
	    ExprKind::Cast     (ref c, _, _) => v.accept(c),

	    ExprKind::And      (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Or       (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Cmp      (_, ref l, ref r) => { v.accept(l); v.accept(r) },
	    ExprKind::Arithm   (_, ref l, ref r) => { v.accept(l); v.accept(r) },

	    ExprKind::Fn     (_, ref args)  => { for e in args.iter() { v.accept(e) } },
			ExprKind::Field  (_) 	          => {},
	    ExprKind::Const  (_)            => {}

	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },
	  }
	}

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait TransformVisitor: Sized
  {
	  fn transform(&self, e: &Expr) -> Expr
	  {
	    transform_by_default(self, e)
	  }
	}

	pub fn transform_by_default<T>(v: &T, e: &Expr) -> Expr
			where T: TransformVisitor + Sized
	{
		match *e.kind() {
	    ExprKind::Not      (ref c)               => Not      (v.transform(c)),
	    ExprKind::IsNull   (ref c)               => IsNull   (v.transform(c)),
	    ExprKind::IsNotNull(ref c)               => IsNotNull(v.transform(c)),
	    ExprKind::PlusSign (ref c)               => PlusSign (v.transform(c)),
	    ExprKind::MinusSign(ref c)               => MinusSign(v.transform(c)),
	    ExprKind::Cast     (ref c, ref f, ref t) => Cast     (v.transform(c), f, t),

	    ExprKind::And      (ref l, ref r)        => And(v.transform(l), v.transform(r)),
	    ExprKind::Or       (ref l, ref r)        => Or (v.transform(l), v.transform(r)),
	    ExprKind::Cmp      (ref o, ref l, ref r) => Cmp(*o, v.transform(l), v.transform(r)),
	    ExprKind::Arithm   (ref o, ref l, ref r) => Arithm(o, e.ty(), v.transform(l), v.transform(r)),

	    ExprKind::Fn       (ref f, ref args)     => {
	    	let rargs = args.iter().map(|arg| v.transform(arg)).collect::<Vec<Expr>>();
	    	Func(f.clone(), rargs)
    	},
			ExprKind::Field     (_) 	                => e.clone(),
	    ExprKind::Const     (_)                   => e.clone(),

	    ExprKind::Switch   (ref cases, ref default)  => {
	    	let rcases = cases.iter().map(|case| v.transform(case)).collect::<Vec<Expr>>();

	    	Switch(rcases, v.transform(default))
   	  }
	    ExprKind::Case      (ref l, ref r)        => Case(v.transform(l), v.transform(r)),
	  }
	}
}<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! fn main() {
//! 	let mut io = IoHandler::default();
//! 	io.add_method("say_hello", |_: Params| {
//! 		Ok(Value::String("hello".to_string()))
//! 	});
//!
//! 	let _server = ServerBuilder::new(io).start_http(&"127.0.0.1:3030".parse().unwrap());
//! }
//! ```

#![warn(missing_docs)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;
extern crate futures;
extern crate tokio_core;

pub mod request_response;
pub mod cors;
mod handler;
mod hosts_validator;
#[cfg(test)]
mod tests;

use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::thread;
use std::collections::HashSet;
use std::ops::Deref;
use hyper::server;
use jsonrpc::MetaIoHandler;
use jsonrpc::reactor::{RpcHandler, RpcEventLoop, RpcEventLoopHandle};

pub use hyper::header::AccessControlAllowOrigin;
pub use handler::{PanicHandler, ServerHandler};
pub use hosts_validator::is_host_header_valid;

/// Result of starting the Server.
pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error.
#[derive(Debug)]
pub enum RpcServerError {
	/// IO Error
	IoError(std::io::Error),
	/// Other Error (hyper)
	Other(hyper::error::Error),
}

impl From<std::io::Error> for RpcServerError {
	fn from(err: std::io::Error) -> Self {
		RpcServerError::IoError(err)
	}
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// Specifies if domains should be validated.
pub enum DomainsValidation<T> {
	/// Allow only domains on the list.
	AllowOnly(Vec<T>),
	/// Disable domains validation completely.
	Disabled,
}

impl<T> Into<Option<Vec<T>>> for DomainsValidation<T> {
	fn into(self) -> Option<Vec<T>> {
		use DomainsValidation::*;
		match self {
			AllowOnly(list) => Some(list),
			Disabled => None,
		}
	}
}

impl<T> From<Option<Vec<T>>> for DomainsValidation<T> {
	fn from(other: Option<Vec<T>>) -> Self {
		match other {
			Some(list) => DomainsValidation::AllowOnly(list),
			None => DomainsValidation::Disabled,
		}
	}
}

/// Extracts metadata from the HTTP request.
pub trait HttpMetaExtractor<M: jsonrpc::Metadata>: Sync + Send + 'static {
	/// Read the metadata from the request
	fn read_metadata(&self, _: &server::Request<hyper::net::HttpStream>) -> M {
		Default::default()
	}
}

#[derive(Default)]
struct NoopExtractor;
impl<M: jsonrpc::Metadata> HttpMetaExtractor<M> for NoopExtractor {}

/// Basic RPC abstraction.
#[derive(Clone)]
pub struct Rpc<M: jsonrpc::Metadata> {
	/// RPC Handler
	pub handler: RpcHandler<M>,
	/// Metadata extractor
	pub extractor: Arc<HttpMetaExtractor<M>>,
}

impl<M: jsonrpc::Metadata> From<RpcHandler<M>> for Rpc<M> {
	fn from(handler: RpcHandler<M>) -> Self {
		Rpc {
			handler: handler,
			extractor: Arc::new(NoopExtractor),
		}
	}
}

impl<M: jsonrpc::Metadata> Deref for Rpc<M> {
	type Target = RpcHandler<M>;

	fn deref(&self) -> &Self::Target {
		&self.handler
	}
}

/// Convenient JSON-RPC HTTP Server builder.
pub struct ServerBuilder<M: jsonrpc::Metadata = ()> {
	jsonrpc_handler: Arc<MetaIoHandler<M>>,
	remote: Option<tokio_core::reactor::Remote>,
	meta_extractor: Arc<HttpMetaExtractor<M>>,
	cors_domains: Option<Vec<AccessControlAllowOrigin>>,
	allowed_hosts: Option<Vec<String>>,
	panic_handler: Option<Box<Fn() -> () + Send>>,
}

impl<M: jsonrpc::Metadata> ServerBuilder<M> {
	/// Creates new `ServerBuilder` for given `IoHandler`.
	///
	/// If you want to re-use the same handler in couple places
	/// see `with_remote` function.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn new<T>(handler: T) -> Self where
		T: Into<MetaIoHandler<M>>
	{
		ServerBuilder {
			jsonrpc_handler: Arc::new(handler.into()),
			remote: None,
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Creates new `ServerBuilder` given access to the event loop `Remote`.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn with_remote(handler: Arc<MetaIoHandler<M>>, remote: tokio_core::reactor::Remote) -> Self {
		ServerBuilder {
			jsonrpc_handler: handler,
			remote: Some(remote),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Sets handler invoked in case of server panic.
	pub fn panic_handler<F>(mut self, handler: F) -> Self where F : Fn() -> () + Send + 'static {
		self.panic_handler = Some(Box::new(handler));
		self
	}

	/// Configures a list of allowed CORS origins.
	pub fn cors(mut self, cors_domains: DomainsValidation<AccessControlAllowOrigin>) -> Self {
		self.cors_domains = cors_domains.into();
		self
	}

	/// Configures metadata extractor
	pub fn meta_extractor(mut self, extractor: Arc<HttpMetaExtractor<M>>) -> Self {
		self.meta_extractor = extractor;
		self
	}

	/// Allow connections only with `Host` header set to binding address.
	pub fn allow_only_bind_host(mut self) -> Self {
		self.allowed_hosts = Some(Vec::new());
		self
	}

	/// Specify a list of valid `Host` headers. Binding address is allowed automatically.
	pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<String>) -> Self {
		self.allowed_hosts = allowed_hosts.into();
		self
	}

	/// Start this JSON-RPC HTTP server trying to bind to specified `SocketAddr`.
	pub fn start_http(self, addr: &SocketAddr) -> ServerResult {
		let panic_for_server = Arc::new(Mutex::new(self.panic_handler));
		let cors_domains = self.cors_domains;
		let hosts = Arc::new(Mutex::new(self.allowed_hosts));
		let hosts_setter = hosts.clone();

		let (handler, event_loop) = match self.remote {
			Some(remote) => (RpcHandler::new(self.jsonrpc_handler, remote), None),
			None => {
				let event_loop = RpcEventLoop::spawn();
				(event_loop.handler(self.jsonrpc_handler), Some(event_loop.into()))
			},
		};

		let jsonrpc_handler = Rpc {
			handler: handler,
			extractor: self.meta_extractor,
		};

		let (l, srv) = try!(try!(hyper::Server::http(addr)).handle(move |control| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			let hosts = hosts.lock().unwrap().clone();
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), hosts, handler, control)
		}));

		// Add current host to allowed headers.
		// NOTE: we need to use `l.addrs()` instead of `addr`
		// it might be different!
		{
			let mut hosts = hosts_setter.lock().unwrap();
			if let Some(current_hosts) = hosts.take() {
				let mut new_hosts = current_hosts.into_iter().collect::<HashSet<_>>();
				for addr in l.addrs() {
					let address = addr.to_string();
					new_hosts.insert(address.clone());
					new_hosts.insert(address.replace("127.0.0.1", "localhost"));
				}
				// Override hosts
				*hosts = Some(new_hosts.into_iter().collect());
			}
		}

		let handle = thread::spawn(move || {
			srv.run();
		});

		Ok(Server {
			server: Some(l),
			handle: Some(handle),
			event_loop: event_loop,
		})
	}
}

/// jsonrpc http server instance
pub struct Server {
	server: Option<server::Listening>,
	handle: Option<thread::JoinHandle<()>>,
	event_loop: Option<RpcEventLoopHandle>,
}

impl Server {
	/// Returns addresses of this server
	pub fn addrs(&self) -> &[SocketAddr] {
		self.server.as_ref().unwrap().addrs()
	}

	/// Closes the server.
	pub fn close(mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}

	/// Will block, waiting for the server to finish.
	pub fn wait(mut self) -> thread::Result<()> {
		self.handle.take().unwrap().join()
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}
}
<commit_msg>HTTP server common with other transports<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! fn main() {
//! 	let mut io = IoHandler::default();
//! 	io.add_method("say_hello", |_: Params| {
//! 		Ok(Value::String("hello".to_string()))
//! 	});
//!
//! 	let _server = ServerBuilder::new(io).start_http(&"127.0.0.1:3030".parse().unwrap());
//! }
//! ```

#![warn(missing_docs)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;
extern crate futures;
extern crate tokio_core;

pub mod request_response;
pub mod cors;
mod handler;
mod hosts_validator;
#[cfg(test)]
mod tests;

use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::thread;
use std::collections::HashSet;
use std::ops::Deref;
use hyper::server;
use jsonrpc::MetaIoHandler;
use jsonrpc::reactor::{RpcHandler, RpcEventLoop, RpcEventLoopHandle};

pub use hyper::header::AccessControlAllowOrigin;
pub use handler::{PanicHandler, ServerHandler};
pub use hosts_validator::is_host_header_valid;

/// Result of starting the Server.
pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error.
#[derive(Debug)]
pub enum RpcServerError {
	/// IO Error
	IoError(std::io::Error),
	/// Other Error (hyper)
	Other(hyper::error::Error),
}

impl From<std::io::Error> for RpcServerError {
	fn from(err: std::io::Error) -> Self {
		RpcServerError::IoError(err)
	}
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// Specifies if domains should be validated.
pub enum DomainsValidation<T> {
	/// Allow only domains on the list.
	AllowOnly(Vec<T>),
	/// Disable domains validation completely.
	Disabled,
}

impl<T> Into<Option<Vec<T>>> for DomainsValidation<T> {
	fn into(self) -> Option<Vec<T>> {
		use DomainsValidation::*;
		match self {
			AllowOnly(list) => Some(list),
			Disabled => None,
		}
	}
}

impl<T> From<Option<Vec<T>>> for DomainsValidation<T> {
	fn from(other: Option<Vec<T>>) -> Self {
		match other {
			Some(list) => DomainsValidation::AllowOnly(list),
			None => DomainsValidation::Disabled,
		}
	}
}

/// Extracts metadata from the HTTP request.
pub trait HttpMetaExtractor<M: jsonrpc::Metadata>: Sync + Send + 'static {
	/// Read the metadata from the request
	fn read_metadata(&self, _: &server::Request<hyper::net::HttpStream>) -> M {
		Default::default()
	}
}

#[derive(Default)]
struct NoopExtractor;
impl<M: jsonrpc::Metadata> HttpMetaExtractor<M> for NoopExtractor {}

/// Basic RPC abstraction.
#[derive(Clone)]
pub struct Rpc<M: jsonrpc::Metadata> {
	/// RPC Handler
	pub handler: RpcHandler<M>,
	/// Metadata extractor
	pub extractor: Arc<HttpMetaExtractor<M>>,
}

impl<M: jsonrpc::Metadata> From<RpcHandler<M>> for Rpc<M> {
	fn from(handler: RpcHandler<M>) -> Self {
		Rpc {
			handler: handler,
			extractor: Arc::new(NoopExtractor),
		}
	}
}

impl<M: jsonrpc::Metadata> Deref for Rpc<M> {
	type Target = RpcHandler<M>;

	fn deref(&self) -> &Self::Target {
		&self.handler
	}
}

enum Handler<M: jsonrpc::Metadata> {
	Simple(MetaIoHandler<M>),
	WithLoop(RpcHandler<M>),
}

/// Convenient JSON-RPC HTTP Server builder.
pub struct ServerBuilder<M: jsonrpc::Metadata = ()> {
	jsonrpc_handler: Handler<M>,
	meta_extractor: Arc<HttpMetaExtractor<M>>,
	cors_domains: Option<Vec<AccessControlAllowOrigin>>,
	allowed_hosts: Option<Vec<String>>,
	panic_handler: Option<Box<Fn() -> () + Send>>,
}

impl<M: jsonrpc::Metadata> ServerBuilder<M> {
	/// Creates new `ServerBuilder` for given `IoHandler`.
	///
	/// If you want to re-use the same handler in couple places
	/// see `with_remote` function.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn new<T>(handler: T) -> Self where
		T: Into<MetaIoHandler<M>>
	{
		ServerBuilder {
			jsonrpc_handler: Handler::Simple(handler.into()),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Creates new `ServerBuilder` given access to the event loop `Remote`.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn with_rpc_handler(handler: RpcHandler<M>) -> Self {
		ServerBuilder {
			jsonrpc_handler: Handler::WithLoop(handler),
			meta_extractor: Arc::new(NoopExtractor::default()),
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Sets handler invoked in case of server panic.
	pub fn panic_handler<F>(mut self, handler: F) -> Self where F : Fn() -> () + Send + 'static {
		self.panic_handler = Some(Box::new(handler));
		self
	}

	/// Configures a list of allowed CORS origins.
	pub fn cors(mut self, cors_domains: DomainsValidation<AccessControlAllowOrigin>) -> Self {
		self.cors_domains = cors_domains.into();
		self
	}

	/// Configures metadata extractor
	pub fn meta_extractor(mut self, extractor: Arc<HttpMetaExtractor<M>>) -> Self {
		self.meta_extractor = extractor;
		self
	}

	/// Allow connections only with `Host` header set to binding address.
	pub fn allow_only_bind_host(mut self) -> Self {
		self.allowed_hosts = Some(Vec::new());
		self
	}

	/// Specify a list of valid `Host` headers. Binding address is allowed automatically.
	pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<String>) -> Self {
		self.allowed_hosts = allowed_hosts.into();
		self
	}

	/// Start this JSON-RPC HTTP server trying to bind to specified `SocketAddr`.
	pub fn start_http(self, addr: &SocketAddr) -> ServerResult {
		let panic_for_server = Arc::new(Mutex::new(self.panic_handler));
		let cors_domains = self.cors_domains;
		let hosts = Arc::new(Mutex::new(self.allowed_hosts));
		let hosts_setter = hosts.clone();

		let (handler, event_loop) = match self.jsonrpc_handler {
			Handler::WithLoop(handler) => (handler, None),
			Handler::Simple(io_handler) => {
				let event_loop = RpcEventLoop::spawn();
				(event_loop.handler(Arc::new(io_handler)), Some(event_loop.into()))
			},
		};

		let jsonrpc_handler = Rpc {
			handler: handler,
			extractor: self.meta_extractor,
		};

		let (l, srv) = try!(try!(hyper::Server::http(addr)).handle(move |control| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			let hosts = hosts.lock().unwrap().clone();
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), hosts, handler, control)
		}));

		// Add current host to allowed headers.
		// NOTE: we need to use `l.addrs()` instead of `addr`
		// it might be different!
		{
			let mut hosts = hosts_setter.lock().unwrap();
			if let Some(current_hosts) = hosts.take() {
				let mut new_hosts = current_hosts.into_iter().collect::<HashSet<_>>();
				for addr in l.addrs() {
					let address = addr.to_string();
					new_hosts.insert(address.clone());
					new_hosts.insert(address.replace("127.0.0.1", "localhost"));
				}
				// Override hosts
				*hosts = Some(new_hosts.into_iter().collect());
			}
		}

		let handle = thread::spawn(move || {
			srv.run();
		});

		Ok(Server {
			server: Some(l),
			handle: Some(handle),
			event_loop: event_loop,
		})
	}
}

/// jsonrpc http server instance
pub struct Server {
	server: Option<server::Listening>,
	handle: Option<thread::JoinHandle<()>>,
	event_loop: Option<RpcEventLoopHandle>,
}

impl Server {
	/// Returns addresses of this server
	pub fn addrs(&self) -> &[SocketAddr] {
		self.server.as_ref().unwrap().addrs()
	}

	/// Closes the server.
	pub fn close(mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}

	/// Will block, waiting for the server to finish.
	pub fn wait(mut self) -> thread::Result<()> {
		self.handle.take().unwrap().join()
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close();
		self.event_loop.take().map(|v| v.close());
	}
}
<|endoftext|>


<commit_before>extern crate vorbis;

use std::io::Write;

fn main() {
    let args = std::env::args();
    args.next();
    // It needs 3 file address as arguments:
    //      first for input vorbis,
    //      second for pcm output file,
    //      third for
    let error = "Error: Usage is <in-ogg-vorbis-file> <out-pcm-file> <out-vorbis-file>";
    let in_file = args.next().expect(error);
    let pcm_file = args.next().expect(error);
    let out_file = args.next().expect(error);
    let in_file = std::fs::File::open(in_file).unwrap();
    let mut decoder = vorbis::Decoder::new(f).unwrap();
    let packets = decoder.packets();
    let mut data = Vec::new();
    let mut channels = 0;
    let mut rate = 0;
    let mut bitrate_upper = 0;
    let mut bitrate_nominal = 0;
    let mut bitrate_lower = 0;
    let mut bitrate_window = 0;
    let mut pcm_file = std::fs::File::create(pcm_file).unwrap();
    for p in packets {
        match p {
            Ok(packet) => {
                channels = packet.channels;
                rate = packet.rate;
                bitrate_upper = packet.bitrate_upper;
                bitrate_nominal = packet.bitrate_nominal;
                bitrate_lower = packet.bitrate_lower;
                bitrate_window = packet.bitrate_window;
                let mut file_data = vec![0u8; packet.data.len() << 1];
                let mut index = 0;
                for sample in packet.data {
                    file_data[index] = (sample as u32 & 255) as u8;
                    index+=1;
                    file_data[index] = ((sample as u32 >> 8) & 255) as u8;
                    index+=1;
                    data.push(sample);
                }
                pcm_file.write(&file_data[..]).unwrap();
            },
            _ => {}
        }
    }
    println!("PCM data size: {}", data.len());
    println!("channels: {:?}", channels);
    println!("rate: {:?}", rate);
    println!("bitrate_upper: {:?}", bitrate_upper);
    println!("bitrate_nominal: {:?}", bitrate_nominal);
    println!("bitrate_lower: {:?}", bitrate_lower);
    println!("bitrate_window: {:?}", bitrate_window);
    let mut encoder = vorbis::Encoder::new(channels as u8, rate, vorbis::VorbisQuality::Midium).expect("Error in creating encoder");
    out_file.write(encoder.encode(&data).expect("Error in encoding.").as_slice()).expect("Error in writing");
    out_file.write(encoder.flush().expect("Error in flushing.").as_slice()).expect("Error in writing");
}
<commit_msg>hmm, stupid bug<commit_after>extern crate vorbis;

use std::io::Write;

fn main() {
    let args = std::env::args();
    args.next();
    // It needs 3 file address as arguments:
    //      first for input vorbis,
    //      second for pcm output file,
    //      third for
    let error = "Error: Usage is <in-ogg-vorbis-file> <out-pcm-file> <out-vorbis-file>";
    let in_file = args.next().expect(error);
    let in_file = std::fs::File::open(in_file).unwrap();
    let pcm_file = args.next().expect(error);
    let mut pcm_file = std::fs::File::create(pcm_file).unwrap();
    let out_file = args.next().expect(error);
    let mut out_file = std::fs::File::create(out_file).unwrap();
    let mut decoder = vorbis::Decoder::new(in_file).unwrap();
    let packets = decoder.packets();
    let mut data = Vec::new();
    let mut channels = 0;
    let mut rate = 0;
    let mut bitrate_upper = 0;
    let mut bitrate_nominal = 0;
    let mut bitrate_lower = 0;
    let mut bitrate_window = 0;
    for p in packets {
        match p {
            Ok(packet) => {
                channels = packet.channels;
                rate = packet.rate;
                bitrate_upper = packet.bitrate_upper;
                bitrate_nominal = packet.bitrate_nominal;
                bitrate_lower = packet.bitrate_lower;
                bitrate_window = packet.bitrate_window;
                let mut file_data = vec![0u8; packet.data.len() << 1];
                let mut index = 0;
                for sample in packet.data {
                    file_data[index] = (sample as u32 & 255) as u8;
                    index+=1;
                    file_data[index] = ((sample as u32 >> 8) & 255) as u8;
                    index+=1;
                    data.push(sample);
                }
                pcm_file.write(&file_data[..]).unwrap();
            },
            _ => {}
        }
    }
    println!("PCM data size: {}", data.len());
    println!("channels: {:?}", channels);
    println!("rate: {:?}", rate);
    println!("bitrate_upper: {:?}", bitrate_upper);
    println!("bitrate_nominal: {:?}", bitrate_nominal);
    println!("bitrate_lower: {:?}", bitrate_lower);
    println!("bitrate_window: {:?}", bitrate_window);
    let mut encoder = vorbis::Encoder::new(channels as u8, rate, vorbis::VorbisQuality::Midium).expect("Error in creating encoder");
    out_file.write(encoder.encode(&data).expect("Error in encoding.").as_slice()).expect("Error in writing");
    out_file.write(encoder.flush().expect("Error in flushing.").as_slice()).expect("Error in writing");
}
<|endoftext|>