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

//! Communication with the compositor thread.

use CompositorMsg as ConstellationMsg;
use compositor::{self, CompositingReason};
use euclid::point::Point2D;
use euclid::size::Size2D;
use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerProperties, PaintListener};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState, PipelineId};
use profile_traits::mem;
use profile_traits::time;
use script_traits::{AnimationState, EventResult, ScriptToCompositorMsg};
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender, channel};
use style_traits::cursor::Cursor;
use style_traits::viewport::ViewportConstraints;
use url::Url;
use windowing::{WindowEvent, WindowMethods};
pub use SendableFrameTree;
pub use windowing;
use webrender;
use webrender_traits;

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
/// process, and so forth.
pub trait CompositorProxy : 'static + Send {
    /// Sends a message to the compositor.
    fn send(&self, msg: Msg);
    /// Clones the compositor proxy.
    fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
}

/// The port that the compositor receives messages on. As above, this is a trait supplied by the
/// Servo port.
pub trait CompositorReceiver : 'static {
    /// Receives the next message inbound for the compositor. This must not block.
    fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
    /// Synchronously waits for, and returns, the next message inbound for the compositor.
    fn recv_compositor_msg(&mut self) -> Msg;
}

/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`.
impl CompositorReceiver for Receiver<Msg> {
    fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
        self.try_recv().ok()
    }
    fn recv_compositor_msg(&mut self) -> Msg {
        self.recv().unwrap()
    }
}

pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'static + Send>,
                                  receiver: IpcReceiver<ScriptToCompositorMsg>) {
    while let Ok(msg) = receiver.recv() {
        match msg {
            ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, smooth) => {
                compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
                                                               layer_id,
                                                               point,
                                                               smooth));
            }

            ScriptToCompositorMsg::GetClientWindow(send) => {
                compositor_proxy.send(Msg::GetClientWindow(send));
            }

            ScriptToCompositorMsg::MoveTo(point) => {
                compositor_proxy.send(Msg::MoveTo(point));
            }

            ScriptToCompositorMsg::ResizeTo(size) => {
                compositor_proxy.send(Msg::ResizeTo(size));
            }

            ScriptToCompositorMsg::Exit => {
                let (chan, port) = ipc::channel().unwrap();
                compositor_proxy.send(Msg::Exit(chan));
                port.recv().unwrap();
            }

            ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
                compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
            }

            ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
                compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
            }

            ScriptToCompositorMsg::TouchEventProcessed(result) => {
                compositor_proxy.send(Msg::TouchEventProcessed(result))
            }

            ScriptToCompositorMsg::GetScrollOffset(pid, lid, send) => {
                compositor_proxy.send(Msg::GetScrollOffset(pid, lid, send));
            }

            ScriptToCompositorMsg::Exited => break,
        }
    }
}

pub trait RenderListener {
    fn recomposite(&mut self, reason: CompositingReason);
}

impl RenderListener for Box<CompositorProxy + 'static> {
    fn recomposite(&mut self, reason: CompositingReason) {
        self.send(Msg::Recomposite(reason));
    }
}

/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
    fn native_display(&mut self) -> Option<NativeDisplay> {
        let (chan, port) = channel();
        self.send(Msg::GetNativeDisplay(chan));
        // If the compositor is shutting down when a paint thread
        // is being created, the compositor won't respond to
        // this message, resulting in an eventual panic. Instead,
        // just return None in this case, since the paint thread
        // will exit shortly and never actually be requested
        // to paint buffers by the compositor.
        port.recv().unwrap_or(None)
    }

    fn assign_painted_buffers(&mut self,
                              pipeline_id: PipelineId,
                              epoch: Epoch,
                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
                              frame_tree_id: FrameTreeId) {
        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
    }

    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
        let mut native_surfaces = Vec::new();
        for request in buffer_requests.into_iter() {
            if let Some(native_surface) = request.native_surface {
                native_surfaces.push(native_surface);
            }
        }
        if !native_surfaces.is_empty() {
            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
        }
    }

    fn initialize_layers_for_pipeline(&mut self,
                                      pipeline_id: PipelineId,
                                      properties: Vec<LayerProperties>,
                                      epoch: Epoch) {
        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
        // that all other layers are immediate children of it. This is sufficient to handle
        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
    }

    fn notify_paint_thread_exiting(&mut self, pipeline_id: PipelineId) {
        self.send(Msg::PaintThreadExited(pipeline_id))
    }
}

/// Messages from the painting thread and the constellation thread to the compositor thread.
pub enum Msg {
    /// Requests that the compositor shut down.
    Exit(IpcSender<()>),

    /// Informs the compositor that the constellation has completed shutdown.
    /// Required because the constellation can have pending calls to make
    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
    ShutdownComplete,

    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
    /// is the pixel format.
    GetNativeDisplay(Sender<Option<NativeDisplay>>),

    /// Tells the compositor to create or update the layers for a pipeline if necessary
    /// (i.e. if no layer with that ID exists).
    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
    /// Scroll a page in a window
    ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
    /// Requests that the compositor assign the painted buffers to the given layers.
    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
    /// Alerts the compositor that the current page has changed its title.
    ChangePageTitle(PipelineId, Option<String>),
    /// Alerts the compositor that the current page has changed its URL.
    ChangePageUrl(PipelineId, Url),
    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
    ChangeRunningAnimationsState(PipelineId, AnimationState),
    /// Replaces the current frame tree, typically called during main frame navigation.
    SetFrameTree(SendableFrameTree, IpcSender<()>, Sender<ConstellationMsg>),
    /// The load of a page has begun: (can go back, can go forward).
    LoadStart(bool, bool),
    /// The load of a page has completed: (can go back, can go forward, is root frame).
    LoadComplete(bool, bool, bool),
    /// We hit the delayed composition timeout. (See `delayed_composition.rs`.)
    DelayedCompositionTimeout(u64),
    /// Composite.
    Recomposite(CompositingReason),
    /// Sends an unconsumed key event back to the compositor.
    KeyEvent(Key, KeyState, KeyModifiers),
    /// Script has handled a touch event, and either prevented or allowed default actions.
    TouchEventProcessed(EventResult),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// Composite to a PNG file and return the Image over a passed channel.
    CreatePng(IpcSender<Option<Image>>),
    /// Informs the compositor that the paint thread for the given pipeline has exited.
    PaintThreadExited(PipelineId),
    /// Alerts the compositor that the viewport has been constrained in some manner
    ViewportConstrained(PipelineId, ViewportConstraints),
    /// A reply to the compositor asking if the output image is stable.
    IsReadyToSaveImageReply(bool),
    /// A favicon was detected
    NewFavicon(Url),
    /// <head> tag finished parsing
    HeadParsed,
    /// Signal that the paint thread ignored the paint requests that carried
    /// these native surfaces, so that they can be re-added to the surface cache.
    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
    /// Collect memory reports and send them back to the given mem::ReportsChan.
    CollectMemoryReports(mem::ReportsChan),
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Get Window Informations size and position
    GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
    /// Move the window to a point
    MoveTo(Point2D<i32>),
    /// Resize the window to size
    ResizeTo(Size2D<u32>),
    /// Get scroll offset of a layer
    GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>),
    /// A pipeline was shut down.
    // This message acts as a synchronization point between the constellation,
    // when it shuts down a pipeline, to the compositor; when the compositor
    // sends a reply on the IpcSender, the constellation knows it's safe to
    // tear down the other threads associated with this pipeline.
    PipelineExited(PipelineId, IpcSender<()>),
}

impl Debug for Msg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Msg::Exit(..) => write!(f, "Exit"),
            Msg::ShutdownComplete => write!(f, "ShutdownComplete"),
            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
            Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
            Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
            Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
            Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
            Msg::LoadComplete(..) => write!(f, "LoadComplete"),
            Msg::LoadStart(..) => write!(f, "LoadStart"),
            Msg::DelayedCompositionTimeout(..) => write!(f, "DelayedCompositionTimeout"),
            Msg::Recomposite(..) => write!(f, "Recomposite"),
            Msg::KeyEvent(..) => write!(f, "KeyEvent"),
            Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
            Msg::SetCursor(..) => write!(f, "SetCursor"),
            Msg::CreatePng(..) => write!(f, "CreatePng"),
            Msg::PaintThreadExited(..) => write!(f, "PaintThreadExited"),
            Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
            Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
            Msg::NewFavicon(..) => write!(f, "NewFavicon"),
            Msg::HeadParsed => write!(f, "HeadParsed"),
            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
            Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
            Msg::Status(..) => write!(f, "Status"),
            Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
            Msg::MoveTo(..) => write!(f, "MoveTo"),
            Msg::ResizeTo(..) => write!(f, "ResizeTo"),
            Msg::PipelineExited(..) => write!(f, "PipelineExited"),
            Msg::GetScrollOffset(..) => write!(f, "GetScrollOffset"),
        }
    }
}

pub struct CompositorThread;

impl CompositorThread {
    pub fn create<Window>(window: Rc<Window>,
                          state: InitialCompositorState)
                          -> Box<CompositorEventListener + 'static>
                          where Window: WindowMethods + 'static {
        box compositor::IOCompositor::create(window, state)
            as Box<CompositorEventListener>
    }
}

pub trait CompositorEventListener {
    fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
    fn repaint_synchronously(&mut self);
    fn pinch_zoom_level(&self) -> f32;
    /// Requests that the compositor send the title for the main frame as soon as possible.
    fn title_for_main_frame(&self);
}

/// Data used to construct a compositor.
pub struct InitialCompositorState {
    /// A channel to the compositor.
    pub sender: Box<CompositorProxy + Send>,
    /// A port on which messages inbound to the compositor can be received.
    pub receiver: Box<CompositorReceiver>,
    /// A channel to the constellation.
    pub constellation_chan: Sender<ConstellationMsg>,
    /// A channel to the time profiler thread.
    pub time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler thread.
    pub mem_profiler_chan: mem::ProfilerChan,
    /// Instance of webrender API if enabled
    pub webrender: Option<webrender::Renderer>,
    pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
<commit_msg>Auto merge of #11334 - Ms2ger:pub-use-compositor_thread, r=Manishearth<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/. */

//! Communication with the compositor thread.

use CompositorMsg as ConstellationMsg;
use SendableFrameTree;
use compositor::{self, CompositingReason};
use euclid::point::Point2D;
use euclid::size::Size2D;
use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerProperties, PaintListener};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState, PipelineId};
use profile_traits::mem;
use profile_traits::time;
use script_traits::{AnimationState, EventResult, ScriptToCompositorMsg};
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use std::sync::mpsc::{Receiver, Sender, channel};
use style_traits::cursor::Cursor;
use style_traits::viewport::ViewportConstraints;
use url::Url;
use webrender;
use webrender_traits;
use windowing::{WindowEvent, WindowMethods};

/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross-
/// process, and so forth.
pub trait CompositorProxy : 'static + Send {
    /// Sends a message to the compositor.
    fn send(&self, msg: Msg);
    /// Clones the compositor proxy.
    fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
}

/// The port that the compositor receives messages on. As above, this is a trait supplied by the
/// Servo port.
pub trait CompositorReceiver : 'static {
    /// Receives the next message inbound for the compositor. This must not block.
    fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
    /// Synchronously waits for, and returns, the next message inbound for the compositor.
    fn recv_compositor_msg(&mut self) -> Msg;
}

/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`.
impl CompositorReceiver for Receiver<Msg> {
    fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
        self.try_recv().ok()
    }
    fn recv_compositor_msg(&mut self) -> Msg {
        self.recv().unwrap()
    }
}

pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'static + Send>,
                                  receiver: IpcReceiver<ScriptToCompositorMsg>) {
    while let Ok(msg) = receiver.recv() {
        match msg {
            ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, smooth) => {
                compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
                                                               layer_id,
                                                               point,
                                                               smooth));
            }

            ScriptToCompositorMsg::GetClientWindow(send) => {
                compositor_proxy.send(Msg::GetClientWindow(send));
            }

            ScriptToCompositorMsg::MoveTo(point) => {
                compositor_proxy.send(Msg::MoveTo(point));
            }

            ScriptToCompositorMsg::ResizeTo(size) => {
                compositor_proxy.send(Msg::ResizeTo(size));
            }

            ScriptToCompositorMsg::Exit => {
                let (chan, port) = ipc::channel().unwrap();
                compositor_proxy.send(Msg::Exit(chan));
                port.recv().unwrap();
            }

            ScriptToCompositorMsg::SetTitle(pipeline_id, title) => {
                compositor_proxy.send(Msg::ChangePageTitle(pipeline_id, title))
            }

            ScriptToCompositorMsg::SendKeyEvent(key, key_state, key_modifiers) => {
                compositor_proxy.send(Msg::KeyEvent(key, key_state, key_modifiers))
            }

            ScriptToCompositorMsg::TouchEventProcessed(result) => {
                compositor_proxy.send(Msg::TouchEventProcessed(result))
            }

            ScriptToCompositorMsg::GetScrollOffset(pid, lid, send) => {
                compositor_proxy.send(Msg::GetScrollOffset(pid, lid, send));
            }

            ScriptToCompositorMsg::Exited => break,
        }
    }
}

pub trait RenderListener {
    fn recomposite(&mut self, reason: CompositingReason);
}

impl RenderListener for Box<CompositorProxy + 'static> {
    fn recomposite(&mut self, reason: CompositingReason) {
        self.send(Msg::Recomposite(reason));
    }
}

/// Implementation of the abstract `PaintListener` interface.
impl PaintListener for Box<CompositorProxy + 'static + Send> {
    fn native_display(&mut self) -> Option<NativeDisplay> {
        let (chan, port) = channel();
        self.send(Msg::GetNativeDisplay(chan));
        // If the compositor is shutting down when a paint thread
        // is being created, the compositor won't respond to
        // this message, resulting in an eventual panic. Instead,
        // just return None in this case, since the paint thread
        // will exit shortly and never actually be requested
        // to paint buffers by the compositor.
        port.recv().unwrap_or(None)
    }

    fn assign_painted_buffers(&mut self,
                              pipeline_id: PipelineId,
                              epoch: Epoch,
                              replies: Vec<(LayerId, Box<LayerBufferSet>)>,
                              frame_tree_id: FrameTreeId) {
        self.send(Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id));
    }

    fn ignore_buffer_requests(&mut self, buffer_requests: Vec<BufferRequest>) {
        let mut native_surfaces = Vec::new();
        for request in buffer_requests.into_iter() {
            if let Some(native_surface) = request.native_surface {
                native_surfaces.push(native_surface);
            }
        }
        if !native_surfaces.is_empty() {
            self.send(Msg::ReturnUnusedNativeSurfaces(native_surfaces));
        }
    }

    fn initialize_layers_for_pipeline(&mut self,
                                      pipeline_id: PipelineId,
                                      properties: Vec<LayerProperties>,
                                      epoch: Epoch) {
        // FIXME(#2004, pcwalton): This assumes that the first layer determines the page size, and
        // that all other layers are immediate children of it. This is sufficient to handle
        // `position: fixed` but will not be sufficient to handle `overflow: scroll` or transforms.
        self.send(Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties));
    }

    fn notify_paint_thread_exiting(&mut self, pipeline_id: PipelineId) {
        self.send(Msg::PaintThreadExited(pipeline_id))
    }
}

/// Messages from the painting thread and the constellation thread to the compositor thread.
pub enum Msg {
    /// Requests that the compositor shut down.
    Exit(IpcSender<()>),

    /// Informs the compositor that the constellation has completed shutdown.
    /// Required because the constellation can have pending calls to make
    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
    ShutdownComplete,

    /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs
    /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
    /// is the pixel format.
    GetNativeDisplay(Sender<Option<NativeDisplay>>),

    /// Tells the compositor to create or update the layers for a pipeline if necessary
    /// (i.e. if no layer with that ID exists).
    InitializeLayersForPipeline(PipelineId, Epoch, Vec<LayerProperties>),
    /// Scroll a page in a window
    ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
    /// Requests that the compositor assign the painted buffers to the given layers.
    AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
    /// Alerts the compositor that the current page has changed its title.
    ChangePageTitle(PipelineId, Option<String>),
    /// Alerts the compositor that the current page has changed its URL.
    ChangePageUrl(PipelineId, Url),
    /// Alerts the compositor that the given pipeline has changed whether it is running animations.
    ChangeRunningAnimationsState(PipelineId, AnimationState),
    /// Replaces the current frame tree, typically called during main frame navigation.
    SetFrameTree(SendableFrameTree, IpcSender<()>, Sender<ConstellationMsg>),
    /// The load of a page has begun: (can go back, can go forward).
    LoadStart(bool, bool),
    /// The load of a page has completed: (can go back, can go forward, is root frame).
    LoadComplete(bool, bool, bool),
    /// We hit the delayed composition timeout. (See `delayed_composition.rs`.)
    DelayedCompositionTimeout(u64),
    /// Composite.
    Recomposite(CompositingReason),
    /// Sends an unconsumed key event back to the compositor.
    KeyEvent(Key, KeyState, KeyModifiers),
    /// Script has handled a touch event, and either prevented or allowed default actions.
    TouchEventProcessed(EventResult),
    /// Changes the cursor.
    SetCursor(Cursor),
    /// Composite to a PNG file and return the Image over a passed channel.
    CreatePng(IpcSender<Option<Image>>),
    /// Informs the compositor that the paint thread for the given pipeline has exited.
    PaintThreadExited(PipelineId),
    /// Alerts the compositor that the viewport has been constrained in some manner
    ViewportConstrained(PipelineId, ViewportConstraints),
    /// A reply to the compositor asking if the output image is stable.
    IsReadyToSaveImageReply(bool),
    /// A favicon was detected
    NewFavicon(Url),
    /// <head> tag finished parsing
    HeadParsed,
    /// Signal that the paint thread ignored the paint requests that carried
    /// these native surfaces, so that they can be re-added to the surface cache.
    ReturnUnusedNativeSurfaces(Vec<NativeSurface>),
    /// Collect memory reports and send them back to the given mem::ReportsChan.
    CollectMemoryReports(mem::ReportsChan),
    /// A status message to be displayed by the browser chrome.
    Status(Option<String>),
    /// Get Window Informations size and position
    GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
    /// Move the window to a point
    MoveTo(Point2D<i32>),
    /// Resize the window to size
    ResizeTo(Size2D<u32>),
    /// Get scroll offset of a layer
    GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>),
    /// A pipeline was shut down.
    // This message acts as a synchronization point between the constellation,
    // when it shuts down a pipeline, to the compositor; when the compositor
    // sends a reply on the IpcSender, the constellation knows it's safe to
    // tear down the other threads associated with this pipeline.
    PipelineExited(PipelineId, IpcSender<()>),
}

impl Debug for Msg {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            Msg::Exit(..) => write!(f, "Exit"),
            Msg::ShutdownComplete => write!(f, "ShutdownComplete"),
            Msg::GetNativeDisplay(..) => write!(f, "GetNativeDisplay"),
            Msg::InitializeLayersForPipeline(..) => write!(f, "InitializeLayersForPipeline"),
            Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"),
            Msg::AssignPaintedBuffers(..) => write!(f, "AssignPaintedBuffers"),
            Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"),
            Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"),
            Msg::ChangePageUrl(..) => write!(f, "ChangePageUrl"),
            Msg::SetFrameTree(..) => write!(f, "SetFrameTree"),
            Msg::LoadComplete(..) => write!(f, "LoadComplete"),
            Msg::LoadStart(..) => write!(f, "LoadStart"),
            Msg::DelayedCompositionTimeout(..) => write!(f, "DelayedCompositionTimeout"),
            Msg::Recomposite(..) => write!(f, "Recomposite"),
            Msg::KeyEvent(..) => write!(f, "KeyEvent"),
            Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
            Msg::SetCursor(..) => write!(f, "SetCursor"),
            Msg::CreatePng(..) => write!(f, "CreatePng"),
            Msg::PaintThreadExited(..) => write!(f, "PaintThreadExited"),
            Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"),
            Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
            Msg::NewFavicon(..) => write!(f, "NewFavicon"),
            Msg::HeadParsed => write!(f, "HeadParsed"),
            Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
            Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
            Msg::Status(..) => write!(f, "Status"),
            Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
            Msg::MoveTo(..) => write!(f, "MoveTo"),
            Msg::ResizeTo(..) => write!(f, "ResizeTo"),
            Msg::PipelineExited(..) => write!(f, "PipelineExited"),
            Msg::GetScrollOffset(..) => write!(f, "GetScrollOffset"),
        }
    }
}

pub struct CompositorThread;

impl CompositorThread {
    pub fn create<Window>(window: Rc<Window>,
                          state: InitialCompositorState)
                          -> Box<CompositorEventListener + 'static>
                          where Window: WindowMethods + 'static {
        box compositor::IOCompositor::create(window, state)
            as Box<CompositorEventListener>
    }
}

pub trait CompositorEventListener {
    fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool;
    fn repaint_synchronously(&mut self);
    fn pinch_zoom_level(&self) -> f32;
    /// Requests that the compositor send the title for the main frame as soon as possible.
    fn title_for_main_frame(&self);
}

/// Data used to construct a compositor.
pub struct InitialCompositorState {
    /// A channel to the compositor.
    pub sender: Box<CompositorProxy + Send>,
    /// A port on which messages inbound to the compositor can be received.
    pub receiver: Box<CompositorReceiver>,
    /// A channel to the constellation.
    pub constellation_chan: Sender<ConstellationMsg>,
    /// A channel to the time profiler thread.
    pub time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler thread.
    pub mem_profiler_chan: mem::ProfilerChan,
    /// Instance of webrender API if enabled
    pub webrender: Option<webrender::Renderer>,
    pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
}
<|endoftext|>


<commit_before>use futures_executor::LocalPool;
use lapin::{
    message::DeliveryResult, options::*, publisher_confirm::Confirmation, types::FieldTable,
    BasicProperties, Connection, ConnectionProperties,
};
use log::info;
use std::{sync::Arc, time::Duration};

fn main() {
    std::env::set_var("RUST_LOG", "info");

    env_logger::init();

    let addr = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "amqp://127.0.0.1:5672/%2f".into());

    LocalPool::new().run_until(async {
        let conn = Connection::connect(&addr, ConnectionProperties::default())
            .await
            .expect("connection error");

        info!("CONNECTED");

        //send channel
        let channel_a = conn.create_channel().await.expect("create_channel");
        //receive channel
        let channel_b = conn.create_channel().await.expect("create_channel");
        info!("[{}] state: {:?}", line!(), conn.status().state());

        //create the hello queue
        let queue = channel_a
            .queue_declare(
                "hello",
                QueueDeclareOptions::default(),
                FieldTable::default(),
            )
            .await
            .expect("queue_declare");
        info!("[{}] state: {:?}", line!(), conn.status().state());
        info!("[{}] declared queue: {:?}", line!(), queue);

        let channel_b = Arc::new(channel_b);
        let chan = channel_b.clone();
        info!("will consume");
        channel_b
            .basic_consume(
                "hello",
                "my_consumer",
                BasicConsumeOptions::default(),
                FieldTable::default(),
            )
            .await
            .expect("basic_consume")
            .set_delegate(move |delivery: DeliveryResult| {
                let chan = chan.clone();
                async move {
                    info!("received message: {:?}", delivery);
                    if let Ok(Some(delivery)) = delivery {
                        chan.basic_ack(delivery.delivery_tag, BasicAckOptions::default())
                            .await
                            .expect("basic_ack");
                        chan.basic_cancel("my_consumer", BasicCancelOptions::default())
                            .await
                            .expect("basic_cancel");
                    }
                }
            });
        info!("[{}] state: {:?}", line!(), conn.status().state());

        info!("will publish");
        let payload = b"Hello world!";
        let confirm = channel_a
            .basic_publish(
                "",
                "hello",
                BasicPublishOptions::default(),
                payload.to_vec(),
                BasicProperties::default(),
            )
            .await
            .expect("basic_publish")
            .await
            .expect("publisher-confirms");
        assert_eq!(confirm, Confirmation::NotRequested);
        info!("[{}] state: {:?}", line!(), conn.status().state());
    });

    std::thread::sleep(Duration::from_secs(2));
}
<commit_msg>examples: use conneciton.run in connection<commit_after>use futures_executor::LocalPool;
use lapin::{
    message::DeliveryResult, options::*, publisher_confirm::Confirmation, types::FieldTable,
    BasicProperties, Connection, ConnectionProperties,
};
use log::info;
use std::sync::Arc;

fn main() {
    std::env::set_var("RUST_LOG", "trace");

    env_logger::init();

    let addr = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "amqp://127.0.0.1:5672/%2f".into());

    LocalPool::new().run_until(async {
        let conn = Connection::connect(&addr, ConnectionProperties::default())
            .await
            .expect("connection error");

        info!("CONNECTED");

        {
            //send channel
            let channel_a = conn.create_channel().await.expect("create_channel");
            //receive channel
            let channel_b = conn.create_channel().await.expect("create_channel");
            info!("[{}] state: {:?}", line!(), conn.status().state());

            //create the hello queue
            let queue = channel_a
                .queue_declare(
                    "hello",
                    QueueDeclareOptions::default(),
                    FieldTable::default(),
                )
                .await
                .expect("queue_declare");
            info!("[{}] state: {:?}", line!(), conn.status().state());
            info!("[{}] declared queue: {:?}", line!(), queue);

            let channel_b = Arc::new(channel_b);
            let chan = channel_b.clone();
            info!("will consume");
            channel_b
                .basic_consume(
                    "hello",
                    "my_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::default(),
                )
                .await
                .expect("basic_consume")
                .set_delegate(move |delivery: DeliveryResult| {
                    let chan = chan.clone();
                    async move {
                        info!("received message: {:?}", delivery);
                        if let Ok(Some(delivery)) = delivery {
                            chan.basic_ack(delivery.delivery_tag, BasicAckOptions::default())
                                .await
                                .expect("basic_ack");
                            chan.basic_cancel("my_consumer", BasicCancelOptions::default())
                                .await
                                .expect("basic_cancel");
                        }
                    }
                });
            info!("[{}] state: {:?}", line!(), conn.status().state());

            info!("will publish");
            let payload = b"Hello world!";
            let confirm = channel_a
                .basic_publish(
                    "",
                    "hello",
                    BasicPublishOptions::default(),
                    payload.to_vec(),
                    BasicProperties::default(),
                )
                .await
                .expect("basic_publish")
                .await
                .expect("publisher-confirms");
            assert_eq!(confirm, Confirmation::NotRequested);
            info!("[{}] state: {:?}", line!(), conn.status().state());
        }

        conn.run().expect("conn.run");
    });
}
<|endoftext|>


<commit_before>use ordered_float::NotNaN;

use bio::stats::probs;

use model;

pub type MeanExpression = NotNaN<f64>;
pub type CDF = probs::cdf::CDF<MeanExpression>;

pub fn cdf(expression_cdfs: &[model::expression::NormalizedCDF], pseudocounts: f64) -> CDF {
    let pseudocounts = NotNaN::new(pseudocounts).unwrap();

    if expression_cdfs.len() == 1 {
        let mut cdf = expression_cdfs[0].clone();
        for e in cdf.iter_mut() {
            e.value += pseudocounts;
        }
        return cdf;
    }

    let cdf = model::meanvar::cdf(expression_cdfs, |mean, _| mean + pseudocounts);
    assert_relative_eq!(cdf.total_prob().exp(), 1.0);
    cdf.reduce().sample(1000)
}

// #[cfg(test)]
// mod tests {
//     #![allow(non_upper_case_globals)]
//
//     use bio::stats::{Prob, LogProb};
//
//     use super::*;
//     use model;
//     use io;
//
//
//     const GENE: &'static str = "COL5A1";
//
//     fn setup() -> Box<model::readout::Model> {
//         model::readout::new_model(
//             &[Prob(0.04); 16],
//             &[Prob(0.1); 16],
//             io::codebook::Codebook::from_file("tests/codebook/140genesData.1.txt").unwrap()
//         )
//     }
//
//     #[test]
//     fn test_cdf() {
//         let readout = setup();
//         let cdfs = [
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0,
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0,
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0,
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0
//         ];
//         println!("{:?}", cdfs[0]);
//         let cdf = cdf(&cdfs, 0.0000001);
//         println!("{:?}", cdf);
//
//         let total = cdf.total_prob();
//
//         assert_relative_eq!(*total, *LogProb::ln_one(), epsilon = 0.002);
//     }
// }
<commit_msg>Minor.<commit_after>use ordered_float::NotNaN;

use bio::stats::probs;

use model;

pub type MeanExpression = NotNaN<f64>;
pub type CDF = probs::cdf::CDF<MeanExpression>;

pub fn cdf(expression_cdfs: &[model::expression::NormalizedCDF], pseudocounts: f64) -> CDF {
    let pseudocounts = NotNaN::new(pseudocounts).unwrap();

    if expression_cdfs.len() == 1 {
        let mut cdf = expression_cdfs[0].clone();
        for e in cdf.iter_mut() {
            e.value += pseudocounts;
        }
        return cdf;
    }

    let cdf = model::meanvar::cdf(expression_cdfs, |mean, _| mean + pseudocounts);
    assert_relative_eq!(cdf.total_prob().exp(), 1.0, epsilon=0.001);
    cdf.reduce().sample(1000)
}

// #[cfg(test)]
// mod tests {
//     #![allow(non_upper_case_globals)]
//
//     use bio::stats::{Prob, LogProb};
//
//     use super::*;
//     use model;
//     use io;
//
//
//     const GENE: &'static str = "COL5A1";
//
//     fn setup() -> Box<model::readout::Model> {
//         model::readout::new_model(
//             &[Prob(0.04); 16],
//             &[Prob(0.1); 16],
//             io::codebook::Codebook::from_file("tests/codebook/140genesData.1.txt").unwrap()
//         )
//     }
//
//     #[test]
//     fn test_cdf() {
//         let readout = setup();
//         let cdfs = [
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0,
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0,
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0,
//             model::expression::cdf(GENE, 5, 5, &readout, 100).0
//         ];
//         println!("{:?}", cdfs[0]);
//         let cdf = cdf(&cdfs, 0.0000001);
//         println!("{:?}", cdf);
//
//         let total = cdf.total_prob();
//
//         assert_relative_eq!(*total, *LogProb::ln_one(), epsilon = 0.002);
//     }
// }
<|endoftext|>


<commit_before>//! This module contains free-standing functions for creating AST fragments out
//! of smaller pieces.
use itertools::Itertools;

use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken};

pub fn name(text: &str) -> ast::Name {
    ast_from_text(&format!("mod {};", text))
}

pub fn name_ref(text: &str) -> ast::NameRef {
    ast_from_text(&format!("fn f() {{ {}; }}", text))
}

pub fn path_from_name_ref(name_ref: ast::NameRef) -> ast::Path {
    path_from_text(&name_ref.syntax().to_string())
}
pub fn path_qualified(qual: ast::Path, name_ref: ast::NameRef) -> ast::Path {
    path_from_text(&format!("{}::{}", qual.syntax(), name_ref.syntax()))
}
fn path_from_text(text: &str) -> ast::Path {
    ast_from_text(text)
}

pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField {
    return match expr {
        Some(expr) => from_text(&format!("{}: {}", name.syntax(), expr.syntax())),
        None => from_text(&name.syntax().to_string()),
    };

    fn from_text(text: &str) -> ast::RecordField {
        ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
    }
}

pub fn block_from_expr(e: ast::Expr) -> ast::Block {
    return from_text(&format!("{{ {} }}", e.syntax()));

    fn from_text(text: &str) -> ast::Block {
        ast_from_text(&format!("fn f() {}", text))
    }
}

pub fn expr_unit() -> ast::Expr {
    expr_from_text("()")
}
pub fn expr_unimplemented() -> ast::Expr {
    expr_from_text("unimplemented!()")
}
pub fn expr_path(path: ast::Path) -> ast::Expr {
    expr_from_text(&path.syntax().to_string())
}
pub fn expr_continue() -> ast::Expr {
    expr_from_text("continue")
}
pub fn expr_break() -> ast::Expr {
    expr_from_text("break")
}
pub fn expr_return() -> ast::Expr {
    expr_from_text("return")
}
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
    expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
}
fn expr_from_text(text: &str) -> ast::Expr {
    ast_from_text(&format!("const C: () = {};", text))
}

pub fn bind_pat(name: ast::Name) -> ast::BindPat {
    return from_text(name.text());

    fn from_text(text: &str) -> ast::BindPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn placeholder_pat() -> ast::PlaceholderPat {
    return from_text("_");

    fn from_text(text: &str) -> ast::PlaceholderPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn tuple_struct_pat(
    path: ast::Path,
    pats: impl IntoIterator<Item = ast::Pat>,
) -> ast::TupleStructPat {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(&format!("{}({})", path.syntax(), pats_str));

    fn from_text(text: &str) -> ast::TupleStructPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str));

    fn from_text(text: &str) -> ast::RecordPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
pub fn path_pat(path: ast::Path) -> ast::Pat {
    let path_str = path.syntax().text().to_string();
    return from_text(path_str.as_str());
    fn from_text(text: &str) -> ast::Pat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(" | ");
    return from_text(&format!("{} => {}", pats_str, expr.syntax()));

    fn from_text(text: &str) -> ast::MatchArm {
        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
    }
}

pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
    let arms_str = arms.into_iter().map(|arm| format!("\n    {}", arm.syntax())).join(",");
    return from_text(&format!("{},\n", arms_str));

    fn from_text(text: &str) -> ast::MatchArmList {
        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
    }
}

pub fn where_pred(
    path: ast::Path,
    bounds: impl IntoIterator<Item = ast::TypeBound>,
) -> ast::WherePred {
    let bounds = bounds.into_iter().map(|b| b.syntax().to_string()).join(" + ");
    return from_text(&format!("{}: {}", path.syntax(), bounds));

    fn from_text(text: &str) -> ast::WherePred {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::WhereClause {
    let preds = preds.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(preds.as_str());

    fn from_text(text: &str) -> ast::WhereClause {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr {
    ast_from_text(&format!(
        "fn f() {{ if !{} {{\n    {}\n}}\n}}",
        condition.syntax().text(),
        statement
    ))
}

pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
    let text = match initializer {
        Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()),
        None => format!("let {};", pattern.syntax()),
    };
    ast_from_text(&format!("fn f() {{ {} }}", text))
}

pub fn token(kind: SyntaxKind) -> SyntaxToken {
    tokens::SOURCE_FILE
        .tree()
        .syntax()
        .descendants_with_tokens()
        .filter_map(|it| it.into_token())
        .find(|it| it.kind() == kind)
        .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
}

fn ast_from_text<N: AstNode>(text: &str) -> N {
    let parse = SourceFile::parse(text);
    parse.tree().syntax().descendants().find_map(N::cast).unwrap()
}

pub mod tokens {
    use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
    use once_cell::sync::Lazy;

    pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
        Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;"));

    pub fn comma() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == T![,])
            .unwrap()
    }

    pub fn single_space() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
            .unwrap()
    }

    pub fn whitespace(text: &str) -> SyntaxToken {
        assert!(text.trim().is_empty());
        let sf = SourceFile::parse(text).ok().unwrap();
        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn single_newline() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
            .unwrap()
    }

    pub struct WsBuilder(SourceFile);

    impl WsBuilder {
        pub fn new(text: &str) -> WsBuilder {
            WsBuilder(SourceFile::parse(text).ok().unwrap())
        }
        pub fn ws(&self) -> SyntaxToken {
            self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
        }
    }
}
<commit_msg>Make sure that newly created nodes are the root of the tree<commit_after>//! This module contains free-standing functions for creating AST fragments out
//! of smaller pieces.
use itertools::Itertools;

use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken};

pub fn name(text: &str) -> ast::Name {
    ast_from_text(&format!("mod {};", text))
}

pub fn name_ref(text: &str) -> ast::NameRef {
    ast_from_text(&format!("fn f() {{ {}; }}", text))
}

pub fn path_from_name_ref(name_ref: ast::NameRef) -> ast::Path {
    path_from_text(&name_ref.syntax().to_string())
}
pub fn path_qualified(qual: ast::Path, name_ref: ast::NameRef) -> ast::Path {
    path_from_text(&format!("{}::{}", qual.syntax(), name_ref.syntax()))
}
fn path_from_text(text: &str) -> ast::Path {
    ast_from_text(text)
}

pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField {
    return match expr {
        Some(expr) => from_text(&format!("{}: {}", name.syntax(), expr.syntax())),
        None => from_text(&name.syntax().to_string()),
    };

    fn from_text(text: &str) -> ast::RecordField {
        ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
    }
}

pub fn block_from_expr(e: ast::Expr) -> ast::Block {
    return from_text(&format!("{{ {} }}", e.syntax()));

    fn from_text(text: &str) -> ast::Block {
        ast_from_text(&format!("fn f() {}", text))
    }
}

pub fn expr_unit() -> ast::Expr {
    expr_from_text("()")
}
pub fn expr_unimplemented() -> ast::Expr {
    expr_from_text("unimplemented!()")
}
pub fn expr_path(path: ast::Path) -> ast::Expr {
    expr_from_text(&path.syntax().to_string())
}
pub fn expr_continue() -> ast::Expr {
    expr_from_text("continue")
}
pub fn expr_break() -> ast::Expr {
    expr_from_text("break")
}
pub fn expr_return() -> ast::Expr {
    expr_from_text("return")
}
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
    expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
}
fn expr_from_text(text: &str) -> ast::Expr {
    ast_from_text(&format!("const C: () = {};", text))
}

pub fn bind_pat(name: ast::Name) -> ast::BindPat {
    return from_text(name.text());

    fn from_text(text: &str) -> ast::BindPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn placeholder_pat() -> ast::PlaceholderPat {
    return from_text("_");

    fn from_text(text: &str) -> ast::PlaceholderPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn tuple_struct_pat(
    path: ast::Path,
    pats: impl IntoIterator<Item = ast::Pat>,
) -> ast::TupleStructPat {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(&format!("{}({})", path.syntax(), pats_str));

    fn from_text(text: &str) -> ast::TupleStructPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str));

    fn from_text(text: &str) -> ast::RecordPat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
pub fn path_pat(path: ast::Path) -> ast::Pat {
    let path_str = path.syntax().text().to_string();
    return from_text(path_str.as_str());
    fn from_text(text: &str) -> ast::Pat {
        ast_from_text(&format!("fn f({}: ())", text))
    }
}

pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm {
    let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(" | ");
    return from_text(&format!("{} => {}", pats_str, expr.syntax()));

    fn from_text(text: &str) -> ast::MatchArm {
        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
    }
}

pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
    let arms_str = arms.into_iter().map(|arm| format!("\n    {}", arm.syntax())).join(",");
    return from_text(&format!("{},\n", arms_str));

    fn from_text(text: &str) -> ast::MatchArmList {
        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
    }
}

pub fn where_pred(
    path: ast::Path,
    bounds: impl IntoIterator<Item = ast::TypeBound>,
) -> ast::WherePred {
    let bounds = bounds.into_iter().map(|b| b.syntax().to_string()).join(" + ");
    return from_text(&format!("{}: {}", path.syntax(), bounds));

    fn from_text(text: &str) -> ast::WherePred {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::WhereClause {
    let preds = preds.into_iter().map(|p| p.syntax().to_string()).join(", ");
    return from_text(preds.as_str());

    fn from_text(text: &str) -> ast::WhereClause {
        ast_from_text(&format!("fn f() where {} {{ }}", text))
    }
}

pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr {
    ast_from_text(&format!(
        "fn f() {{ if !{} {{\n    {}\n}}\n}}",
        condition.syntax().text(),
        statement
    ))
}

pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
    let text = match initializer {
        Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()),
        None => format!("let {};", pattern.syntax()),
    };
    ast_from_text(&format!("fn f() {{ {} }}", text))
}

pub fn token(kind: SyntaxKind) -> SyntaxToken {
    tokens::SOURCE_FILE
        .tree()
        .syntax()
        .descendants_with_tokens()
        .filter_map(|it| it.into_token())
        .find(|it| it.kind() == kind)
        .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
}

fn ast_from_text<N: AstNode>(text: &str) -> N {
    let parse = SourceFile::parse(text);
    let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
    let node = node.syntax().clone();
    let node = unroot(node);
    let node = N::cast(node).unwrap();
    assert_eq!(node.syntax().text_range().start(), 0.into());
    node
}

fn unroot(n: SyntaxNode) -> SyntaxNode {
    SyntaxNode::new_root(n.green().clone())
}

pub mod tokens {
    use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
    use once_cell::sync::Lazy;

    pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
        Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;"));

    pub fn comma() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == T![,])
            .unwrap()
    }

    pub fn single_space() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
            .unwrap()
    }

    pub fn whitespace(text: &str) -> SyntaxToken {
        assert!(text.trim().is_empty());
        let sf = SourceFile::parse(text).ok().unwrap();
        sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
    }

    pub fn single_newline() -> SyntaxToken {
        SOURCE_FILE
            .tree()
            .syntax()
            .descendants_with_tokens()
            .filter_map(|it| it.into_token())
            .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
            .unwrap()
    }

    pub struct WsBuilder(SourceFile);

    impl WsBuilder {
        pub fn new(text: &str) -> WsBuilder {
            WsBuilder(SourceFile::parse(text).ok().unwrap())
        }
        pub fn ws(&self) -> SyntaxToken {
            self.0.syntax().first_child_or_token().unwrap().into_token().unwrap()
        }
    }
}
<|endoftext|>


<commit_before>use std::{collections::BTreeMap, convert::TryInto, fmt, marker::PhantomData};

use js_int::Int;
use serde::{
    de::{self, Deserializer, IntoDeserializer as _, MapAccess, Visitor},
    ser::Serializer,
    Deserialize, Serialize,
};

/// Serde deserialization decorator to map empty Strings to None,
/// and forward non-empty Strings to the Deserialize implementation for T.
/// Useful for the typical
/// "A room with an X event with an absent, null, or empty Y field
/// should be treated the same as a room with no such event."
/// formulation in the spec.
///
/// To be used like this:
/// `#[serde(deserialize_with = "empty_string_as_none")]`
/// Relevant serde issue: <https://github.com/serde-rs/serde/issues/1425>
pub fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de>,
{
    let opt = Option::<String>::deserialize(de)?;
    match opt.as_deref() {
        None | Some("") => Ok(None),
        // If T = String, like in m.room.name, the second deserialize is actually superfluous.
        // TODO: optimize that somehow?
        Some(s) => T::deserialize(s.into_deserializer()).map(Some),
    }
}

/// Serde serializiation decorator to map None to an empty String,
/// and forward Somes to the Serialize implemention for T.
///
/// To be used like this:
/// `#[serde(serialize_with = "empty_string_as_none")]`
pub fn none_as_empty_string<T: Serialize, S>(
    value: &Option<T>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    match value {
        Some(x) => x.serialize(serializer),
        None => serializer.serialize_str(""),
    }
}

/// Take either an integer number or a string and deserialize to an integer number.
///
/// To be used like this:
/// `#[serde(deserialize_with = "int_or_string_to_int")]`
pub fn int_or_string_to_int<'de, D>(de: D) -> Result<Int, D::Error>
where
    D: Deserializer<'de>,
{
    struct IntOrStringVisitor;

    impl<'de> Visitor<'de> for IntOrStringVisitor {
        type Value = Int;

        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
            formatter.write_str("an integer or a string")
        }

        fn visit_i8<E: de::Error>(self, v: i8) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_i16<E: de::Error>(self, v: i16) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_i32<E: de::Error>(self, v: i32) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_i128<E: de::Error>(self, v: i128) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_u16<E: de::Error>(self, v: u16) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_u32<E: de::Error>(self, v: u32) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_u128<E: de::Error>(self, v: u128) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
            v.parse().map_err(E::custom)
        }
    }

    de.deserialize_any(IntOrStringVisitor)
}

/// Take a BTreeMap with values of either an integer number or a string and deserialize
/// those to integer numbers.
///
/// To be used like this:
/// `#[serde(deserialize_with = "btreemap_int_or_string_to_int_values")]`
pub fn btreemap_int_or_string_to_int_values<'de, D, T>(de: D) -> Result<BTreeMap<T, Int>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de> + Ord,
{
    #[repr(transparent)]
    struct IntWrap(Int);

    impl<'de> Deserialize<'de> for IntWrap {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            int_or_string_to_int(deserializer).map(IntWrap)
        }
    }

    struct IntMapVisitor<T> {
        _phantom: PhantomData<T>,
    }

    impl<T> IntMapVisitor<T> {
        fn new() -> Self {
            Self { _phantom: PhantomData }
        }
    }

    impl<'de, T> Visitor<'de> for IntMapVisitor<T>
    where
        T: Deserialize<'de> + Ord,
    {
        type Value = BTreeMap<T, Int>;

        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
            formatter.write_str("a map with integers or stings as values")
        }

        fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
            let mut res = BTreeMap::new();

            while let Some((k, IntWrap(v))) = map.next_entry()? {
                res.insert(k, v);
            }

            Ok(res)
        }
    }

    de.deserialize_map(IntMapVisitor::new())
}

#[cfg(test)]
mod tests {
    use js_int::{int, Int};
    use matches::assert_matches;
    use serde::Deserialize;

    use super::int_or_string_to_int;

    #[test]
    fn int_or_string() -> serde_json::Result<()> {
        #[derive(Debug, Deserialize)]
        struct Test {
            #[serde(deserialize_with = "int_or_string_to_int")]
            num: Int,
        }

        assert_matches!(
            serde_json::from_value::<Test>(serde_json::json!({ "num": "0" }))?,
            Test { num } if num == int!(0)
        );

        Ok(())
    }
}
<commit_msg>Update example on ruma_serde::empty_string_as_none<commit_after>use std::{collections::BTreeMap, convert::TryInto, fmt, marker::PhantomData};

use js_int::Int;
use serde::{
    de::{self, Deserializer, IntoDeserializer as _, MapAccess, Visitor},
    ser::Serializer,
    Deserialize, Serialize,
};

/// Serde deserialization decorator to map empty Strings to None,
/// and forward non-empty Strings to the Deserialize implementation for T.
/// Useful for the typical
/// "A room with an X event with an absent, null, or empty Y field
/// should be treated the same as a room with no such event."
/// formulation in the spec.
///
/// To be used like this:
/// `#[serde(default, deserialize_with = "empty_string_as_none")]`
/// Relevant serde issue: <https://github.com/serde-rs/serde/issues/1425>
pub fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de>,
{
    let opt = Option::<String>::deserialize(de)?;
    match opt.as_deref() {
        None | Some("") => Ok(None),
        // If T = String, like in m.room.name, the second deserialize is actually superfluous.
        // TODO: optimize that somehow?
        Some(s) => T::deserialize(s.into_deserializer()).map(Some),
    }
}

/// Serde serializiation decorator to map None to an empty String,
/// and forward Somes to the Serialize implemention for T.
///
/// To be used like this:
/// `#[serde(serialize_with = "empty_string_as_none")]`
pub fn none_as_empty_string<T: Serialize, S>(
    value: &Option<T>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    match value {
        Some(x) => x.serialize(serializer),
        None => serializer.serialize_str(""),
    }
}

/// Take either an integer number or a string and deserialize to an integer number.
///
/// To be used like this:
/// `#[serde(deserialize_with = "int_or_string_to_int")]`
pub fn int_or_string_to_int<'de, D>(de: D) -> Result<Int, D::Error>
where
    D: Deserializer<'de>,
{
    struct IntOrStringVisitor;

    impl<'de> Visitor<'de> for IntOrStringVisitor {
        type Value = Int;

        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
            formatter.write_str("an integer or a string")
        }

        fn visit_i8<E: de::Error>(self, v: i8) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_i16<E: de::Error>(self, v: i16) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_i32<E: de::Error>(self, v: i32) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_i128<E: de::Error>(self, v: i128) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_u16<E: de::Error>(self, v: u16) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_u32<E: de::Error>(self, v: u32) -> Result<Self::Value, E> {
            Ok(v.into())
        }

        fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_u128<E: de::Error>(self, v: u128) -> Result<Self::Value, E> {
            v.try_into().map_err(E::custom)
        }

        fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
            v.parse().map_err(E::custom)
        }
    }

    de.deserialize_any(IntOrStringVisitor)
}

/// Take a BTreeMap with values of either an integer number or a string and deserialize
/// those to integer numbers.
///
/// To be used like this:
/// `#[serde(deserialize_with = "btreemap_int_or_string_to_int_values")]`
pub fn btreemap_int_or_string_to_int_values<'de, D, T>(de: D) -> Result<BTreeMap<T, Int>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de> + Ord,
{
    #[repr(transparent)]
    struct IntWrap(Int);

    impl<'de> Deserialize<'de> for IntWrap {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            int_or_string_to_int(deserializer).map(IntWrap)
        }
    }

    struct IntMapVisitor<T> {
        _phantom: PhantomData<T>,
    }

    impl<T> IntMapVisitor<T> {
        fn new() -> Self {
            Self { _phantom: PhantomData }
        }
    }

    impl<'de, T> Visitor<'de> for IntMapVisitor<T>
    where
        T: Deserialize<'de> + Ord,
    {
        type Value = BTreeMap<T, Int>;

        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
            formatter.write_str("a map with integers or stings as values")
        }

        fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
            let mut res = BTreeMap::new();

            while let Some((k, IntWrap(v))) = map.next_entry()? {
                res.insert(k, v);
            }

            Ok(res)
        }
    }

    de.deserialize_map(IntMapVisitor::new())
}

#[cfg(test)]
mod tests {
    use js_int::{int, Int};
    use matches::assert_matches;
    use serde::Deserialize;

    use super::int_or_string_to_int;

    #[test]
    fn int_or_string() -> serde_json::Result<()> {
        #[derive(Debug, Deserialize)]
        struct Test {
            #[serde(deserialize_with = "int_or_string_to_int")]
            num: Int,
        }

        assert_matches!(
            serde_json::from_value::<Test>(serde_json::json!({ "num": "0" }))?,
            Test { num } if num == int!(0)
        );

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


<commit_before>use libc;

use std::char;
use std::io::{self, Write};
use std::mem;
use std::process;
use std::str;
use std::thread;
use std::time::Duration;

use crate::boots;
use crate::gc::{Address, GcReason};
use crate::handle::{scope as handle_scope, Handle};
use crate::object::{Obj, Ref, Str, UInt8Array};
use crate::stack::stacktrace_from_last_dtn;
use crate::threads::{DoraThread, STACK_SIZE, THREAD};
use crate::ty::SourceTypeArray;
use crate::vm::{get_vm, stack_pointer, Trap};

pub extern "C" fn uint8_to_string(val: u8) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn char_to_string(val: u32) -> Ref<Str> {
    handle_scope(|| {
        let buffer = unsafe { char::from_u32_unchecked(val) }.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn int32_to_string(val: i32) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn int64_to_string(val: i64) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn float32_to_string(val: f32) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn float64_to_string(val: f64) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn print(val: Handle<Str>) {
    io::stdout().write(val.content()).unwrap();
}

pub extern "C" fn fatal_error(msg: Handle<Str>) {
    eprint!("fatal error: ");
    io::stderr().write(msg.content()).unwrap();
    eprintln!("");

    let vm = get_vm();
    let stacktrace = stacktrace_from_last_dtn(vm);
    stacktrace.dump_err(vm);

    process::exit(1);
}

pub extern "C" fn abort() {
    eprintln!("program aborted.");
    process::exit(1);
}

pub extern "C" fn exit(status: i32) {
    process::exit(status);
}

pub extern "C" fn unreachable() {
    eprintln!("unreachable code executed.");
    process::exit(1);
}

pub extern "C" fn timestamp() -> u64 {
    use crate::timer;

    timer::timestamp()
}

pub extern "C" fn println(val: Handle<Str>) {
    let stdout = io::stdout();
    let mut handle = stdout.lock();
    handle.write(val.content()).unwrap();
    handle.write(b"\n").unwrap();
}

pub extern "C" fn sleep(seconds: i32) {
    assert!(seconds >= 0);
    thread::sleep(Duration::from_secs(seconds as u64));
}

pub extern "C" fn call(fct: Handle<Str>) {
    let fct_name = fct.to_cstring();
    let fct_name = fct_name.to_str().unwrap();

    let vm = get_vm();
    let name = vm.interner.intern(fct_name);

    if let Some(fct_id) = vm
        .namespace_table(vm.global_namespace_id)
        .read()
        .get_fct(name)
    {
        {
            let fct = vm.fcts.idx(fct_id);
            let fct = fct.read();

            if !fct.param_types.is_empty() {
                writeln!(&mut io::stderr(), "fct `{}` takes arguments.", fct_name)
                    .expect("could not print to stderr");
                process::exit(1);
            }
        }

        vm.run(fct_id);
    } else {
        writeln!(&mut io::stderr(), "fct `{}` not found.", fct_name)
            .expect("could not print to stderr");
        process::exit(1);
    }
}

pub extern "C" fn bytecode(name: Handle<Str>) -> Ref<Obj> {
    let fct_name = name.to_cstring();
    let fct_name = fct_name.to_str().unwrap();

    let vm = get_vm();

    boots::bytecode(vm, &fct_name)
}

pub extern "C" fn strcmp(lhs: Handle<Str>, rhs: Handle<Str>) -> i32 {
    unsafe {
        libc::strcmp(
            lhs.data() as *const libc::c_char,
            rhs.data() as *const libc::c_char,
        )
    }
}

pub extern "C" fn strcat(lhs: Handle<Str>, rhs: Handle<Str>) -> Ref<Str> {
    handle_scope(|| {
        let vm = get_vm();
        Str::concat(vm, lhs, rhs).direct()
    })
}

pub extern "C" fn str_clone(val: Handle<Str>) -> Ref<Str> {
    handle_scope(|| {
        let vm = get_vm();

        val.dup(vm)
    })
}

pub extern "C" fn str_from_bytes(val: Handle<UInt8Array>, offset: usize, len: usize) -> Ref<Str> {
    handle_scope(|| {
        let vm = get_vm();
        let val: Handle<Str> = val.cast();

        Str::from_str(vm, val, offset, len)
    })
}

pub extern "C" fn gc_alloc(size: usize, array_ref: bool) -> *mut Obj {
    let vm = get_vm();
    vm.gc.alloc(vm, size, array_ref).to_mut_ptr()
}

pub extern "C" fn gc_collect() {
    let vm = get_vm();
    vm.gc.collect(vm, GcReason::ForceCollect);
}

pub extern "C" fn gc_minor_collect() {
    let vm = get_vm();
    vm.gc.minor_collect(vm, GcReason::ForceMinorCollect);
}

pub extern "C" fn argc() -> i32 {
    let vm = get_vm();

    if let Some(ref args) = vm.args.arg_argument {
        args.len() as i32
    } else {
        0
    }
}

pub extern "C" fn argv(ind: i32) -> Ref<Str> {
    let vm = get_vm();

    if let Some(ref args) = vm.args.arg_argument {
        if ind >= 0 && ind < args.len() as i32 {
            let value = &args[ind as usize];

            return Str::from_buffer(vm, value.as_bytes());
        }
    }

    panic!("argument does not exist");
}

pub extern "C" fn str_to_int32_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i32>().is_ok()
}

pub extern "C" fn str_to_int32(val: Handle<Str>) -> i32 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i32>().unwrap_or(0)
}

pub extern "C" fn str_to_int64_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i64>().is_ok()
}

pub extern "C" fn str_to_int64(val: Handle<Str>) -> i64 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i64>().unwrap_or(0)
}

pub extern "C" fn str_to_float32_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f32>().is_ok()
}

pub extern "C" fn str_to_float32(val: Handle<Str>) -> f32 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f32>().unwrap_or(0.0f32)
}

pub extern "C" fn str_to_float64_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f64>().is_ok()
}

pub extern "C" fn str_to_float64(val: Handle<Str>) -> f64 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f64>().unwrap_or(0.0)
}

pub extern "C" fn trap(trap_id: u32) {
    let vm = get_vm();
    let trap = Trap::from(trap_id).expect("invalid trap id!");

    let msg = match trap {
        Trap::DIV0 => "division by 0",
        Trap::ASSERT => "assert failed",
        Trap::INDEX_OUT_OF_BOUNDS => "array index out of bounds",
        Trap::NIL => "nil check failed",
        Trap::CAST => "cast failed",
        Trap::OOM => "out of memory",
        Trap::STACK_OVERFLOW => "stack overflow",
        Trap::ILLEGAL => "illegal state",
    };

    eprintln!("{}", msg);
    let stacktrace = stacktrace_from_last_dtn(vm);
    stacktrace.dump_err(vm);
    unsafe {
        libc::_exit(100 + trap_id as i32);
    }
}

pub extern "C" fn spawn_thread(obj: Handle<Obj>) {
    use crate::compiler;
    use crate::stack::DoraToNativeInfo;

    let vm = get_vm();

    // Create new thread in Parked state.
    let thread = DoraThread::new(vm);

    // Add thread to our list of all threads first. This method parks
    // and unparks the current thread, this means the handle needs to be created
    // afterwards.
    vm.threads.attach_thread(vm, thread.clone());

    // Now we can create a handle for that newly created thread. Since the thread
    // is now registered, the handle is updated as well by the GC.
    let location = thread.handles.handle(obj.direct()).location();

    thread::spawn(move || {
        // Initialize thread-local variable with thread
        THREAD.with(|thread_local_thread| {
            *thread_local_thread.borrow_mut() = thread;
        });

        let handle: Handle<Obj> = Handle::from_address(location);

        let stack_top = stack_pointer();
        let stack_limit = stack_top.sub(STACK_SIZE);

        THREAD.with(|thread| {
            thread.borrow().tld.set_stack_limit(stack_limit);
            thread.borrow().unpark(vm);
        });

        let main = {
            let cls_id = handle.header().vtbl().class_def().cls_id;
            let cls_id = cls_id.expect("no corresponding class");
            let cls = vm.classes.idx(cls_id);
            let cls = cls.read();
            let name = vm.interner.intern("run");
            cls.find_method(vm, name, false)
                .expect("run() method not found")
        };

        let tld = THREAD.with(|thread| {
            let thread = thread.borrow();
            let ptr = &thread.tld;

            Address::from_ptr(ptr as *const _)
        });

        let fct_ptr = {
            let mut dtn = DoraToNativeInfo::new();
            let type_params = SourceTypeArray::empty();

            THREAD.with(|thread| {
                thread
                    .borrow()
                    .use_dtn(&mut dtn, || compiler::generate(vm, main, &type_params))
            })
        };

        // execute the thread object's run-method
        let dora_stub_address = vm.dora_stub();
        let fct: extern "C" fn(Address, Address, Ref<Obj>) =
            unsafe { mem::transmute(dora_stub_address) };
        fct(tld, fct_ptr, handle.direct());

        // remove thread from list of all threads
        vm.threads.detach_current_thread();
    });
}

pub extern "C" fn join_thread(_obj: Handle<Obj>) {
    unimplemented!()
}
<commit_msg>add comment to handle creation in spawn_thread<commit_after>use libc;

use std::char;
use std::io::{self, Write};
use std::mem;
use std::process;
use std::str;
use std::thread;
use std::time::Duration;

use crate::boots;
use crate::gc::{Address, GcReason};
use crate::handle::{scope as handle_scope, Handle};
use crate::object::{Obj, Ref, Str, UInt8Array};
use crate::stack::stacktrace_from_last_dtn;
use crate::threads::{DoraThread, STACK_SIZE, THREAD};
use crate::ty::SourceTypeArray;
use crate::vm::{get_vm, stack_pointer, Trap};

pub extern "C" fn uint8_to_string(val: u8) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn char_to_string(val: u32) -> Ref<Str> {
    handle_scope(|| {
        let buffer = unsafe { char::from_u32_unchecked(val) }.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn int32_to_string(val: i32) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn int64_to_string(val: i64) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn float32_to_string(val: f32) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn float64_to_string(val: f64) -> Ref<Str> {
    handle_scope(|| {
        let buffer = val.to_string();
        let vm = get_vm();

        Str::from_buffer(vm, buffer.as_bytes())
    })
}

pub extern "C" fn print(val: Handle<Str>) {
    io::stdout().write(val.content()).unwrap();
}

pub extern "C" fn fatal_error(msg: Handle<Str>) {
    eprint!("fatal error: ");
    io::stderr().write(msg.content()).unwrap();
    eprintln!("");

    let vm = get_vm();
    let stacktrace = stacktrace_from_last_dtn(vm);
    stacktrace.dump_err(vm);

    process::exit(1);
}

pub extern "C" fn abort() {
    eprintln!("program aborted.");
    process::exit(1);
}

pub extern "C" fn exit(status: i32) {
    process::exit(status);
}

pub extern "C" fn unreachable() {
    eprintln!("unreachable code executed.");
    process::exit(1);
}

pub extern "C" fn timestamp() -> u64 {
    use crate::timer;

    timer::timestamp()
}

pub extern "C" fn println(val: Handle<Str>) {
    let stdout = io::stdout();
    let mut handle = stdout.lock();
    handle.write(val.content()).unwrap();
    handle.write(b"\n").unwrap();
}

pub extern "C" fn sleep(seconds: i32) {
    assert!(seconds >= 0);
    thread::sleep(Duration::from_secs(seconds as u64));
}

pub extern "C" fn call(fct: Handle<Str>) {
    let fct_name = fct.to_cstring();
    let fct_name = fct_name.to_str().unwrap();

    let vm = get_vm();
    let name = vm.interner.intern(fct_name);

    if let Some(fct_id) = vm
        .namespace_table(vm.global_namespace_id)
        .read()
        .get_fct(name)
    {
        {
            let fct = vm.fcts.idx(fct_id);
            let fct = fct.read();

            if !fct.param_types.is_empty() {
                writeln!(&mut io::stderr(), "fct `{}` takes arguments.", fct_name)
                    .expect("could not print to stderr");
                process::exit(1);
            }
        }

        vm.run(fct_id);
    } else {
        writeln!(&mut io::stderr(), "fct `{}` not found.", fct_name)
            .expect("could not print to stderr");
        process::exit(1);
    }
}

pub extern "C" fn bytecode(name: Handle<Str>) -> Ref<Obj> {
    let fct_name = name.to_cstring();
    let fct_name = fct_name.to_str().unwrap();

    let vm = get_vm();

    boots::bytecode(vm, &fct_name)
}

pub extern "C" fn strcmp(lhs: Handle<Str>, rhs: Handle<Str>) -> i32 {
    unsafe {
        libc::strcmp(
            lhs.data() as *const libc::c_char,
            rhs.data() as *const libc::c_char,
        )
    }
}

pub extern "C" fn strcat(lhs: Handle<Str>, rhs: Handle<Str>) -> Ref<Str> {
    handle_scope(|| {
        let vm = get_vm();
        Str::concat(vm, lhs, rhs).direct()
    })
}

pub extern "C" fn str_clone(val: Handle<Str>) -> Ref<Str> {
    handle_scope(|| {
        let vm = get_vm();

        val.dup(vm)
    })
}

pub extern "C" fn str_from_bytes(val: Handle<UInt8Array>, offset: usize, len: usize) -> Ref<Str> {
    handle_scope(|| {
        let vm = get_vm();
        let val: Handle<Str> = val.cast();

        Str::from_str(vm, val, offset, len)
    })
}

pub extern "C" fn gc_alloc(size: usize, array_ref: bool) -> *mut Obj {
    let vm = get_vm();
    vm.gc.alloc(vm, size, array_ref).to_mut_ptr()
}

pub extern "C" fn gc_collect() {
    let vm = get_vm();
    vm.gc.collect(vm, GcReason::ForceCollect);
}

pub extern "C" fn gc_minor_collect() {
    let vm = get_vm();
    vm.gc.minor_collect(vm, GcReason::ForceMinorCollect);
}

pub extern "C" fn argc() -> i32 {
    let vm = get_vm();

    if let Some(ref args) = vm.args.arg_argument {
        args.len() as i32
    } else {
        0
    }
}

pub extern "C" fn argv(ind: i32) -> Ref<Str> {
    let vm = get_vm();

    if let Some(ref args) = vm.args.arg_argument {
        if ind >= 0 && ind < args.len() as i32 {
            let value = &args[ind as usize];

            return Str::from_buffer(vm, value.as_bytes());
        }
    }

    panic!("argument does not exist");
}

pub extern "C" fn str_to_int32_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i32>().is_ok()
}

pub extern "C" fn str_to_int32(val: Handle<Str>) -> i32 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i32>().unwrap_or(0)
}

pub extern "C" fn str_to_int64_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i64>().is_ok()
}

pub extern "C" fn str_to_int64(val: Handle<Str>) -> i64 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<i64>().unwrap_or(0)
}

pub extern "C" fn str_to_float32_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f32>().is_ok()
}

pub extern "C" fn str_to_float32(val: Handle<Str>) -> f32 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f32>().unwrap_or(0.0f32)
}

pub extern "C" fn str_to_float64_success(val: Handle<Str>) -> bool {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f64>().is_ok()
}

pub extern "C" fn str_to_float64(val: Handle<Str>) -> f64 {
    let slice = val.content();
    let val = str::from_utf8(slice).unwrap();

    val.parse::<f64>().unwrap_or(0.0)
}

pub extern "C" fn trap(trap_id: u32) {
    let vm = get_vm();
    let trap = Trap::from(trap_id).expect("invalid trap id!");

    let msg = match trap {
        Trap::DIV0 => "division by 0",
        Trap::ASSERT => "assert failed",
        Trap::INDEX_OUT_OF_BOUNDS => "array index out of bounds",
        Trap::NIL => "nil check failed",
        Trap::CAST => "cast failed",
        Trap::OOM => "out of memory",
        Trap::STACK_OVERFLOW => "stack overflow",
        Trap::ILLEGAL => "illegal state",
    };

    eprintln!("{}", msg);
    let stacktrace = stacktrace_from_last_dtn(vm);
    stacktrace.dump_err(vm);
    unsafe {
        libc::_exit(100 + trap_id as i32);
    }
}

pub extern "C" fn spawn_thread(obj: Handle<Obj>) {
    use crate::compiler;
    use crate::stack::DoraToNativeInfo;

    let vm = get_vm();

    // Create new thread in Parked state.
    let thread = DoraThread::new(vm);

    // Add thread to our list of all threads first. This method parks
    // and unparks the current thread, this means the handle needs to be created
    // afterwards.
    vm.threads.attach_thread(vm, thread.clone());

    // Now we can create a handle for that newly created thread. Since the thread
    // is now registered, the handle is updated as well by the GC.
    // We create the handle in the new Parked thread, normally this would be unsafe.
    // Here it should be safe though, because the current thread is still Running
    // and therefore the GC can't run at this point.
    THREAD.with(|thread| {
        debug_assert!(thread.borrow().state_relaxed().is_running());
    });
    let location = thread.handles.handle(obj.direct()).location();

    thread::spawn(move || {
        // Initialize thread-local variable with thread
        THREAD.with(|thread_local_thread| {
            *thread_local_thread.borrow_mut() = thread;
        });

        let handle: Handle<Obj> = Handle::from_address(location);

        let stack_top = stack_pointer();
        let stack_limit = stack_top.sub(STACK_SIZE);

        THREAD.with(|thread| {
            thread.borrow().tld.set_stack_limit(stack_limit);
            thread.borrow().unpark(vm);
        });

        let main = {
            let cls_id = handle.header().vtbl().class_def().cls_id;
            let cls_id = cls_id.expect("no corresponding class");
            let cls = vm.classes.idx(cls_id);
            let cls = cls.read();
            let name = vm.interner.intern("run");
            cls.find_method(vm, name, false)
                .expect("run() method not found")
        };

        let tld = THREAD.with(|thread| {
            let thread = thread.borrow();
            let ptr = &thread.tld;

            Address::from_ptr(ptr as *const _)
        });

        let fct_ptr = {
            let mut dtn = DoraToNativeInfo::new();
            let type_params = SourceTypeArray::empty();

            THREAD.with(|thread| {
                thread
                    .borrow()
                    .use_dtn(&mut dtn, || compiler::generate(vm, main, &type_params))
            })
        };

        // execute the thread object's run-method
        let dora_stub_address = vm.dora_stub();
        let fct: extern "C" fn(Address, Address, Ref<Obj>) =
            unsafe { mem::transmute(dora_stub_address) };
        fct(tld, fct_ptr, handle.direct());

        // remove thread from list of all threads
        vm.threads.detach_current_thread();
    });
}

pub extern "C" fn join_thread(_obj: Handle<Obj>) {
    unimplemented!()
}
<|endoftext|>