<commit_before>use async::*;
use async::camera::CameraData;
use async::mesh_renderer::MeshRendererData;
use async::resource::{MaterialId, MeshId};
use async::scheduler::WorkId;
use async::transform::{TransformInnerHandle, TransformGraph};
use cell_extras::{AtomicInitCell, InitCell};
use bootstrap::window::{Message, Window};
use polygon::{GpuMesh, Renderer, RendererBuilder};
use polygon::anchor::Anchor;
use polygon::camera::{Camera as RenderCamera, CameraId};
use polygon::mesh_instance::MeshInstance;
use std::collections::HashMap;
use std::mem;
use std::ptr::{self, Unique};
use std::sync::{Arc, Barrier};
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;

#[derive(Debug)]
pub struct EngineBuilder {
    max_workers: usize,
}

static INSTANCE: AtomicInitCell<Unique<Engine>> = AtomicInitCell::new();
static MAIN_LOOP: AtomicInitCell<WorkId> = AtomicInitCell::new();

/// A builder for configuring the components and systems registered with the game engine.
///
/// Component managers and systems cannot be changed once the engine has been instantiated so they
/// must be provided all together when the instance is created. `EngineBuilder` provides an
/// interface for gathering all managers and systems to be provided to the engine.
impl EngineBuilder {
    /// Creates a new `EngineBuilder` object.
    pub fn new() -> EngineBuilder {
        EngineBuilder {
            max_workers: 1,
        }
    }

    /// Consumes the builder and creates the `Engine` instance.
    ///
    /// `func` is invoked once the engine has been setup, so `func` should kick off all game
    /// functionality.
    ///
    /// No `Engine` object is returned because this method instantiates the engine singleton.
    pub fn build<F>(self, func: F)
        where F: FnOnce()
    {
        let window = {
            let mut window = unsafe { mem::uninitialized() };
            let mut out = unsafe { Unique::new(&mut window as *mut _) };

            let barrier = Arc::new(Barrier::new(2));
            let barrier_clone = barrier.clone();

            thread::spawn(move || {
                let mut window = Window::new("gunship game").unwrap();

                let mut message_pump = window.message_pump();

                // write data out to `window` without dropping the old (uninitialized) value.
                unsafe { ptr::write(out.get_mut(), window); }

                // Sync with
                barrier_clone.wait();

                // We're done using the barrier, drop it so that the `Arc` can deallocate once
                // the other thread has receieved the Window.
                mem::drop(barrier_clone);

                message_pump.run();
            });

            // Wait until window thread finishe creating the window.
            barrier.wait();

            window
        };

        let renderer = RendererBuilder::new(&window).build();
        let (sender, receiever) = mpsc::channel();

        // Init aysnc subsystem.
        scheduler::init_thread();

        // Spawn our worker threads.
        if self.max_workers > 0 {
            for _ in 0..self.max_workers - 1 {
                let sender = sender.clone();
                thread::spawn(move || {
                    // Initialize thread-local renderer message channel.
                    RENDER_MESSAGE_CHANNEL.with(move |channel| { channel.init(sender); });

                    // Initialize worker thread to support fibers and wait for work to be available.
                    scheduler::run_wait_fiber();
                });
            }
        }

        // Set the current thread's channel.
        RENDER_MESSAGE_CHANNEL.with(move |channel| { channel.init(sender); });

        let engine = Engine {
            window: window,
            renderer: renderer,
            channel: receiever,

            mesh_map: HashMap::new(),

            scene_graph: TransformGraph::new(),
            camera: None,
            behaviors: Vec::new(),
        };

        let main_loop = scheduler::start(move || { main_loop(engine); });

        MAIN_LOOP.init(main_loop.work_id());

        func();

        wait_for_quit();
    }

    pub fn max_workers(&mut self, workers: usize) -> &mut EngineBuilder {
        assert!(workers > 0, "There must be at least one worker for the engine to run");
        self.max_workers = workers;
        self
    }
}

pub struct Engine {
    window: Window,

    renderer: Box<Renderer>,
    channel: Receiver<EngineMessage>,

    mesh_map: HashMap<MeshId, GpuMesh>,

    scene_graph: TransformGraph,
    camera: Option<(Box<CameraData>, CameraId)>,
    behaviors: Vec<Box<FnMut() + Send + Sync>>,
}

impl Drop for Engine {
    fn drop(&mut self) {
        // TODO: Clear instance?
    }
}

// `Engine` does handles synchronization internally, so it's meant be shared between threads.
unsafe impl Send for Engine {}
unsafe impl Sync for Engine {}

thread_local! {
    // TODO: We don't want this to be completely public, only pub(crate), but `thread_local`
    // doesn't support pub(crate) syntax.
    pub static RENDER_MESSAGE_CHANNEL: InitCell<Sender<EngineMessage>> = InitCell::new();
}

pub fn scene_graph<F, T>(func: F) -> T
    where F: FnOnce(&TransformGraph) -> T
{
    let engine = INSTANCE.borrow();
    unsafe { func(&(***engine).scene_graph) }
}

pub enum EngineMessage {
    Anchor(TransformInnerHandle),
    Camera(Box<CameraData>, TransformInnerHandle),
    Material(MaterialId, ::polygon::material::MaterialSource),
    Mesh(MeshId, ::polygon::geometry::mesh::Mesh),
    MeshInstance(Box<MeshRendererData>, TransformInnerHandle),
    Behavior(Box<FnMut() + Send + Sync>),
}

pub fn send_message(message: EngineMessage) {
    RENDER_MESSAGE_CHANNEL.with(move |channel| {
        channel
            .send(message)
            .expect("Unable to send render resource message");
    });
}

pub fn run_each_frame<F>(func: F)
    where
    F: 'static,
    F: FnMut(),
    F: Send + Sync,
{
    send_message(EngineMessage::Behavior(Box::new(func)));
}

/// Suspends the calling worker until the engine main loop has finished.
pub fn wait_for_quit() {
    MAIN_LOOP.borrow().await();
}

fn main_loop(engine: Engine) {
    let mut engine = Box::new(engine);
    INSTANCE.init(unsafe { Unique::new(&mut *engine) });
    let engine = &mut *engine;

    'main: loop {
        // Process any pending window messages.
        for message in &mut engine.window {
            // TODO: Process input messages.
            if let Message::Close = message {
                break 'main;
            }
        }

        // Kick off all game behaviors and wait for them to complete.
        if engine.behaviors.len() > 0 {
            let mut pending = Vec::with_capacity(engine.behaviors.len());

            // Start all behaviors...
            for behavior in engine.behaviors.iter_mut() {
                let async = scheduler::start(&mut **behavior);
                pending.push(async);
            }

            // ... then wait for each of them to finish.
            for async in pending {
                async.await();
            }
        } else {
            // There are no per-frame behaviors. We suspend the main loop fiber anyway to give
            // other work some time on the thread. Generally this case only matters when debugging
            // with a single thread.
            scheduler::suspend();
        }

        // Before drawing, process any pending render messages. These will be resources that were
        // loaded but need to be registered with the renderer before the next draw.
        while let Ok(message) = engine.channel.try_recv() {
            match message {
                EngineMessage::Anchor(transform_inner) => {
                    let anchor = Anchor::new();
                    let anchor_id = engine.renderer.register_anchor(anchor);

                    transform_inner.set_anchor(anchor_id);
                },
                EngineMessage::Camera(camera_data, transform_inner) => {
                    assert!(engine.camera.is_none(), "Can't add camera, one is already registered");

                    let anchor_id = match transform_inner.anchor() {
                        Some(anchor) => anchor,
                        None => unimplemented!(), // TODO: Create the anchor.
                    };

                    let mut camera = RenderCamera::default();
                    camera.set_anchor(anchor_id);
                    let camera_id = engine.renderer.register_camera(camera);

                    engine.camera = Some((camera_data, camera_id));
                },
                EngineMessage::Material(_material_id, material_source) => {
                    let material = engine.renderer.build_material(material_source).expect("TODO: Handle material compilation failure");
                    let _gpu_material = engine.renderer.register_material(material);

                    // TODO: Create an association between `material_id` and `material_source`.
                },
                EngineMessage::Mesh(mesh_id, mesh_data) => {
                    let gpu_mesh = engine.renderer.register_mesh(&mesh_data);
                    let last = engine.mesh_map.insert(mesh_id, gpu_mesh);
                    assert!(last.is_none(), "Duplicate mesh_id found: {:?}", mesh_id);
                },
                EngineMessage::MeshInstance(mesh_renderer_data, transform_inner) => {
                    let anchor_id = match transform_inner.anchor() {
                        Some(anchor) => anchor,
                        None => unimplemented!(), // TODO: Create the anchor.
                    };

                    let gpu_mesh = *engine
                        .mesh_map
                        .get(&mesh_renderer_data.mesh_id())
                        .expect("No gpu mesh found for mesh id");

                    let mut mesh_instance = MeshInstance::new(
                        gpu_mesh,
                        engine.renderer.default_material(),
                    );
                    mesh_instance.material_mut().set_color("surface_color", ::math::Color::rgb(1.0, 0.0, 0.0)); // HACK HACK HACK
                    mesh_instance.set_anchor(anchor_id);

                    let _ = engine.renderer.register_mesh_instance(mesh_instance);
                }
                EngineMessage::Behavior(func) => {
                    engine.behaviors.push(func);
                }
            }
        }

        // Update renderer's anchors with flattened scene graph.
        for node in engine.scene_graph.roots() {
            let node = node.borrow();

            // TODO: Do something like pre-sorting so we only try to update out of
            // date nodes.
            if let Some(anchor_id) = node.anchor() {
                // Send position/rotation/scale to renderer anchor.
                let anchor = engine.renderer
                    .get_anchor_mut(anchor_id)
                    .expect("Node had anchor id but render did not have specified anchor");
                anchor.set_position(node.position);
                anchor.set_orientation(node.orientation);
                anchor.set_scale(node.scale);
            }
        }

        // Update the camera.
        if let Some((ref camera_data, ref camera_id)) = engine.camera {
            let render_camera = engine.renderer
                .get_camera_mut(*camera_id)
                .expect("Camera didn't exist for camera id");

            render_camera.set_fov(camera_data.fov());
            render_camera.set_aspect(camera_data.aspect());
            render_camera.set_near(camera_data.near());
            render_camera.set_far(camera_data.far());
        }

        // TODO: Draw.
        engine.renderer.draw();

        // TODO: Wait for frame time?
    }
}
<commit_msg>Await frame time in main loop<commit_after>use async::*;
use async::camera::CameraData;
use async::mesh_renderer::MeshRendererData;
use async::resource::{MaterialId, MeshId};
use async::scheduler::WorkId;
use async::transform::{TransformInnerHandle, TransformGraph};
use cell_extras::{AtomicInitCell, InitCell};
use bootstrap::window::{Message, Window};
use polygon::{GpuMesh, Renderer, RendererBuilder};
use polygon::anchor::Anchor;
use polygon::camera::{Camera as RenderCamera, CameraId};
use polygon::mesh_instance::MeshInstance;
use std::collections::HashMap;
use std::mem;
use std::ptr::{self, Unique};
use std::sync::{Arc, Barrier};
use std::sync::mpsc::{self, Receiver, Sender};
use std::time::{Duration, Instant};
use std::thread;

#[derive(Debug)]
pub struct EngineBuilder {
    max_workers: usize,
}

static INSTANCE: AtomicInitCell<Unique<Engine>> = AtomicInitCell::new();
static MAIN_LOOP: AtomicInitCell<WorkId> = AtomicInitCell::new();

/// A builder for configuring the components and systems registered with the game engine.
///
/// Component managers and systems cannot be changed once the engine has been instantiated so they
/// must be provided all together when the instance is created. `EngineBuilder` provides an
/// interface for gathering all managers and systems to be provided to the engine.
impl EngineBuilder {
    /// Creates a new `EngineBuilder` object.
    pub fn new() -> EngineBuilder {
        EngineBuilder {
            max_workers: 1,
        }
    }

    /// Consumes the builder and creates the `Engine` instance.
    ///
    /// `func` is invoked once the engine has been setup, so `func` should kick off all game
    /// functionality.
    ///
    /// No `Engine` object is returned because this method instantiates the engine singleton.
    pub fn build<F>(self, func: F)
        where F: FnOnce()
    {
        let window = {
            let mut window = unsafe { mem::uninitialized() };
            let mut out = unsafe { Unique::new(&mut window as *mut _) };

            let barrier = Arc::new(Barrier::new(2));
            let barrier_clone = barrier.clone();

            thread::spawn(move || {
                let mut window = Window::new("gunship game").unwrap();

                let mut message_pump = window.message_pump();

                // write data out to `window` without dropping the old (uninitialized) value.
                unsafe { ptr::write(out.get_mut(), window); }

                // Sync with
                barrier_clone.wait();

                // We're done using the barrier, drop it so that the `Arc` can deallocate once
                // the other thread has receieved the Window.
                mem::drop(barrier_clone);

                message_pump.run();
            });

            // Wait until window thread finishe creating the window.
            barrier.wait();

            window
        };

        let renderer = RendererBuilder::new(&window).build();
        let (sender, receiever) = mpsc::channel();

        // Init aysnc subsystem.
        scheduler::init_thread();

        // Spawn our worker threads.
        if self.max_workers > 0 {
            for _ in 0..self.max_workers - 1 {
                let sender = sender.clone();
                thread::spawn(move || {
                    // Initialize thread-local renderer message channel.
                    RENDER_MESSAGE_CHANNEL.with(move |channel| { channel.init(sender); });

                    // Initialize worker thread to support fibers and wait for work to be available.
                    scheduler::run_wait_fiber();
                });
            }
        }

        // Set the current thread's channel.
        RENDER_MESSAGE_CHANNEL.with(move |channel| { channel.init(sender); });

        let engine = Engine {
            window: window,
            renderer: renderer,
            channel: receiever,

            mesh_map: HashMap::new(),

            scene_graph: TransformGraph::new(),
            camera: None,
            behaviors: Vec::new(),
        };

        let main_loop = scheduler::start(move || { main_loop(engine); });

        MAIN_LOOP.init(main_loop.work_id());

        func();

        wait_for_quit();
    }

    pub fn max_workers(&mut self, workers: usize) -> &mut EngineBuilder {
        assert!(workers > 0, "There must be at least one worker for the engine to run");
        self.max_workers = workers;
        self
    }
}

pub struct Engine {
    window: Window,

    renderer: Box<Renderer>,
    channel: Receiver<EngineMessage>,

    mesh_map: HashMap<MeshId, GpuMesh>,

    scene_graph: TransformGraph,
    camera: Option<(Box<CameraData>, CameraId)>,
    behaviors: Vec<Box<FnMut() + Send + Sync>>,
}

impl Drop for Engine {
    fn drop(&mut self) {
        // TODO: Clear instance?
    }
}

// `Engine` does handles synchronization internally, so it's meant be shared between threads.
unsafe impl Send for Engine {}
unsafe impl Sync for Engine {}

thread_local! {
    // TODO: We don't want this to be completely public, only pub(crate), but `thread_local`
    // doesn't support pub(crate) syntax.
    pub static RENDER_MESSAGE_CHANNEL: InitCell<Sender<EngineMessage>> = InitCell::new();
}

pub fn scene_graph<F, T>(func: F) -> T
    where F: FnOnce(&TransformGraph) -> T
{
    let engine = INSTANCE.borrow();
    unsafe { func(&(***engine).scene_graph) }
}

pub enum EngineMessage {
    Anchor(TransformInnerHandle),
    Camera(Box<CameraData>, TransformInnerHandle),
    Material(MaterialId, ::polygon::material::MaterialSource),
    Mesh(MeshId, ::polygon::geometry::mesh::Mesh),
    MeshInstance(Box<MeshRendererData>, TransformInnerHandle),
    Behavior(Box<FnMut() + Send + Sync>),
}

pub fn send_message(message: EngineMessage) {
    RENDER_MESSAGE_CHANNEL.with(move |channel| {
        channel
            .send(message)
            .expect("Unable to send render resource message");
    });
}

pub fn run_each_frame<F>(func: F)
    where
    F: 'static,
    F: FnMut(),
    F: Send + Sync,
{
    send_message(EngineMessage::Behavior(Box::new(func)));
}

/// Suspends the calling worker until the engine main loop has finished.
pub fn wait_for_quit() {
    MAIN_LOOP.borrow().await();
}

fn main_loop(engine: Engine) {
    // TODO: This should be a constant, but we can't create constant `Duration` objects right now.
    let target_frame_time = Duration::from_millis(1000 / 60);

    let mut engine = Box::new(engine);
    INSTANCE.init(unsafe { Unique::new(&mut *engine) });
    let engine = &mut *engine;

    'main: loop {
        let start_time = Instant::now();

        // Process any pending window messages.
        for message in &mut engine.window {
            // TODO: Process input messages.
            if let Message::Close = message {
                break 'main;
            }
        }

        // Kick off all game behaviors and wait for them to complete.
        if engine.behaviors.len() > 0 {
            let mut pending = Vec::with_capacity(engine.behaviors.len());

            // Start all behaviors...
            for behavior in engine.behaviors.iter_mut() {
                let async = scheduler::start(&mut **behavior);
                pending.push(async);
            }

            // ... then wait for each of them to finish.
            for async in pending {
                async.await();
            }
        } else {
            // There are no per-frame behaviors. We suspend the main loop fiber anyway to give
            // other work some time on the thread. Generally this case only matters when debugging
            // with a single thread.
            scheduler::suspend();
        }

        // Before drawing, process any pending render messages. These will be resources that were
        // loaded but need to be registered with the renderer before the next draw.
        while let Ok(message) = engine.channel.try_recv() {
            match message {
                EngineMessage::Anchor(transform_inner) => {
                    let anchor = Anchor::new();
                    let anchor_id = engine.renderer.register_anchor(anchor);

                    transform_inner.set_anchor(anchor_id);
                },
                EngineMessage::Camera(camera_data, transform_inner) => {
                    assert!(engine.camera.is_none(), "Can't add camera, one is already registered");

                    let anchor_id = match transform_inner.anchor() {
                        Some(anchor) => anchor,
                        None => unimplemented!(), // TODO: Create the anchor.
                    };

                    let mut camera = RenderCamera::default();
                    camera.set_anchor(anchor_id);
                    let camera_id = engine.renderer.register_camera(camera);

                    engine.camera = Some((camera_data, camera_id));
                },
                EngineMessage::Material(_material_id, material_source) => {
                    let material = engine.renderer.build_material(material_source).expect("TODO: Handle material compilation failure");
                    let _gpu_material = engine.renderer.register_material(material);

                    // TODO: Create an association between `material_id` and `material_source`.
                },
                EngineMessage::Mesh(mesh_id, mesh_data) => {
                    let gpu_mesh = engine.renderer.register_mesh(&mesh_data);
                    let last = engine.mesh_map.insert(mesh_id, gpu_mesh);
                    assert!(last.is_none(), "Duplicate mesh_id found: {:?}", mesh_id);
                },
                EngineMessage::MeshInstance(mesh_renderer_data, transform_inner) => {
                    let anchor_id = match transform_inner.anchor() {
                        Some(anchor) => anchor,
                        None => unimplemented!(), // TODO: Create the anchor.
                    };

                    let gpu_mesh = *engine
                        .mesh_map
                        .get(&mesh_renderer_data.mesh_id())
                        .expect("No gpu mesh found for mesh id");

                    let mut mesh_instance = MeshInstance::new(
                        gpu_mesh,
                        engine.renderer.default_material(),
                    );
                    mesh_instance.material_mut().set_color("surface_color", ::math::Color::rgb(1.0, 0.0, 0.0)); // HACK HACK HACK
                    mesh_instance.set_anchor(anchor_id);

                    let _ = engine.renderer.register_mesh_instance(mesh_instance);
                }
                EngineMessage::Behavior(func) => {
                    engine.behaviors.push(func);
                }
            }
        }

        // Update renderer's anchors with flattened scene graph.
        for node in engine.scene_graph.roots() {
            let node = node.borrow();

            // TODO: Do something like pre-sorting so we only try to update out of
            // date nodes.
            if let Some(anchor_id) = node.anchor() {
                // Send position/rotation/scale to renderer anchor.
                let anchor = engine.renderer
                    .get_anchor_mut(anchor_id)
                    .expect("Node had anchor id but render did not have specified anchor");
                anchor.set_position(node.position);
                anchor.set_orientation(node.orientation);
                anchor.set_scale(node.scale);
            }
        }

        // Update the camera.
        if let Some((ref camera_data, ref camera_id)) = engine.camera {
            let render_camera = engine.renderer
                .get_camera_mut(*camera_id)
                .expect("Camera didn't exist for camera id");

            render_camera.set_fov(camera_data.fov());
            render_camera.set_aspect(camera_data.aspect());
            render_camera.set_near(camera_data.near());
            render_camera.set_far(camera_data.far());
        }

        // TODO: Draw.
        engine.renderer.draw();

        // If we've already exceeded the frame time then we don't want run the wait code below
        // as the subtraction will overflow.
        if start_time.elapsed() > target_frame_time {
            if !cfg!(feature = "timing") {
                println!(
                    "WARNING: Missed frame time. Frame time: {:?}, target frame time: {:?}",
                    start_time.elapsed(),
                    target_frame_time,
                );
            }

            continue;
        }

        // Sleep the thread while there's more than a millisecond left.
        let mut remaining_time_ms = target_frame_time - start_time.elapsed();
        while remaining_time_ms > Duration::from_millis(1) {
            thread::sleep(remaining_time_ms);

            if start_time.elapsed() > target_frame_time {
                continue 'main;
            } else {
                remaining_time_ms = target_frame_time - start_time.elapsed();
            }
        }

        // When there's less than a millisecond left the system scheduler isn't accurate enough to
        // awake it at the right time and it's possible to sleep too long. To avoid that we simply
        // busy loop until it's time for the next frame.
        while start_time.elapsed() < target_frame_time {}
    }
}
<|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/.

#![allow(clippy::doc_markdown)]

#[macro_use]
extern crate log;

use std::{
    cell::RefCell,
    env,
    fs::{File, OpenOptions},
    io::{Read, Write},
    os::unix::io::{AsRawFd, RawFd},
    process::exit,
    rc::Rc,
};

use chrono::Duration;
use clap::{App, Arg, ArgMatches};
use env_logger::Builder;
use log::LevelFilter;
use nix::{
    fcntl::{flock, FlockArg},
    sys::{
        signal::{self, SigSet},
        signalfd::{SfdFlags, SignalFd},
    },
    unistd::getpid,
};
use uuid::Uuid;

#[cfg(feature = "dbus_enabled")]
use libstratis::{
    dbus_api::{DbusConnectionData, EventHandler},
    engine::get_engine_listener_list_mut,
};

use libstratis::{
    engine::{Engine, Pool, SimEngine, StratEngine},
    stratis::{buff_log, StratisError, StratisResult, VERSION},
};

const STRATISD_PID_PATH: &str = "/run/stratisd.pid";

/// Number of minutes to buffer log entries.
const DEFAULT_LOG_HOLD_MINUTES: i64 = 30;

/// Configure the env_logger as necessary in order to allow the buffered
/// logger to work correctly. Return a Handle to the underlying env_logger.
pub fn from_env_logger(
    mut builder: env_logger::Builder,
    pass_through: bool,
    hold_time: Option<Duration>,
) -> buff_log::Handle<env_logger::Logger> {
    // Do not have the env_logger set the timestamp. Because the entries are
    // buffered, the timestamp set by the env_logger will correspond to the
    // time at which the entry was dumped, not the time of its origination.
    builder.default_format_timestamp(false);
    buff_log::Logger::new(builder.build(), pass_through, hold_time).init()
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> buff_log::Handle<env_logger::Logger> {
    let mut builder = Builder::new();
    if debug {
        builder.filter(Some("stratisd"), LevelFilter::Debug);
        builder.filter(Some("libstratis"), LevelFilter::Debug);
        from_env_logger(builder, true, None)
    } else {
        builder.filter_level(LevelFilter::Trace);
        if let Ok(s) = env::var("RUST_LOG") {
            builder.parse(&s);
        }
        from_env_logger(
            builder,
            false,
            Some(Duration::minutes(DEFAULT_LOG_HOLD_MINUTES)),
        )
    }
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn trylock_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)
        .map_err(|err| {
            StratisError::Error(format!(
                "Failed to create or open the stratisd PID file at {}: {}",
                STRATISD_PID_PATH, err
            ))
        })?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write_all(getpid().to_string().as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;

            Err(StratisError::Error(format!(
                "Daemon already running with supposed pid: {}",
                buf
            )))
        }
    }
}

// Conditionally compiled support for a D-Bus interface.
struct MaybeDbusSupport {
    #[cfg(feature = "dbus_enabled")]
    handle: Option<libstratis::dbus_api::DbusConnectionData>,
}

// If D-Bus compiled out, do very little.
#[cfg(not(feature = "dbus_enabled"))]
impl MaybeDbusSupport {
    fn new() -> MaybeDbusSupport {
        MaybeDbusSupport {}
    }

    fn process(
        &mut self,
        _engine: &Rc<RefCell<dyn Engine>>,
        _fds: &mut Vec<libc::pollfd>,
        _dbus_client_index_start: usize,
    ) {
    }

    fn register_pool(&mut self, _pool_uuid: Uuid, _pool: &mut dyn Pool) {}

    fn poll_timeout(&self) -> i32 {
        // Non-DBus timeout is infinite
        -1
    }
}

#[cfg(feature = "dbus_enabled")]
impl MaybeDbusSupport {
    fn new() -> MaybeDbusSupport {
        MaybeDbusSupport { handle: None }
    }

    /// Connect to D-Bus and register pools, if not already connected.
    /// Return the connection, if made or already existing, otherwise, None.
    fn setup_connection(
        &mut self,
        engine: &Rc<RefCell<dyn Engine>>,
    ) -> Option<&mut DbusConnectionData> {
        if self.handle.is_none() {
            match libstratis::dbus_api::DbusConnectionData::connect(Rc::clone(engine)) {
                Err(err) => {
                    warn!("D-Bus API is not available: {}", err);
                }
                Ok(mut handle) => {
                    info!("D-Bus API is available");
                    let event_handler = Box::new(EventHandler::new(Rc::clone(&handle.connection)));
                    get_engine_listener_list_mut().register_listener(event_handler);
                    // Register all the pools with dbus
                    for (_, pool_uuid, pool) in engine.borrow_mut().pools_mut() {
                        handle.register_pool(pool_uuid, pool)
                    }
                    self.handle = Some(handle);
                }
            }
        };
        self.handle.as_mut()
    }

    /// Handle any client dbus requests.
    fn process(
        &mut self,
        engine: &Rc<RefCell<dyn Engine>>,
        fds: &mut Vec<libc::pollfd>,
        dbus_client_index_start: usize,
    ) {
        if let Some(handle) = self.setup_connection(engine) {
            handle.handle(&fds[dbus_client_index_start..]);

            // Refresh list of dbus fds to poll for. This can change as
            // D-Bus clients come and go.
            fds.truncate(dbus_client_index_start);
            fds.extend(
                handle
                    .connection
                    .borrow()
                    .watch_fds()
                    .iter()
                    .map(|w| w.to_pollfd()),
            );
        }
    }

    fn register_pool(&mut self, pool_uuid: Uuid, pool: &mut dyn Pool) {
        if let Some(h) = self.handle.as_mut() {
            h.register_pool(pool_uuid, pool)
        }
    }

    fn poll_timeout(&self) -> i32 {
        // If there is no D-Bus connection set timeout to 1 sec (1000 ms), so
        // that stratisd can periodically attempt to set up a connection.
        // If the connection is up, set the timeout to infinite; there is no
        // need to poll as events will be received.
        self.handle.as_ref().map_or(1000, |_| -1)
    }
}

// A facility for listening for and handling udev events that stratisd
// considers interesting.
struct UdevMonitor<'a> {
    socket: libudev::MonitorSocket<'a>,
}

impl<'a> UdevMonitor<'a> {
    fn create(context: &'a libudev::Context) -> StratisResult<UdevMonitor<'a>> {
        let mut monitor = libudev::Monitor::new(context)?;
        monitor.match_subsystem("block")?;

        Ok(UdevMonitor {
            socket: monitor.listen()?,
        })
    }

    fn as_raw_fd(&mut self) -> RawFd {
        self.socket.as_raw_fd()
    }

    /// Handle udev events.
    /// Check if a pool can be constructed and update engine and D-Bus layer
    /// data structures if so.
    fn handle_events(&mut self, engine: &mut dyn Engine, dbus_support: &mut MaybeDbusSupport) {
        while let Some(event) = self.socket.receive_event() {
            if let Some((pool_uuid, pool)) = engine.handle_event(&event) {
                dbus_support.register_pool(pool_uuid, pool);
            }
        }
    }
}

// Process any pending signals, return true if SIGINT received.
// Return an error if there was an error reading the signal.
fn process_signal(
    sfd: &mut SignalFd,
    buff_log: &buff_log::Handle<env_logger::Logger>,
) -> StratisResult<bool> {
    match sfd.read_signal() {
        // This is an unsafe conversion, but in this context that is
        // mostly harmless. A negative converted value, which is
        // virtually impossible, will not match any of the masked
        // values, and stratisd will panic and exit.
        Ok(Some(sig)) => match sig.ssi_signo as i32 {
            nix::libc::SIGUSR1 => {
                info!(
                    "SIGUSR1 received, dumping {} buffered log entries",
                    buff_log.buffered_count()
                );
                buff_log.dump();
                Ok(false)
            }
            nix::libc::SIGINT => {
                info!("SIGINT received, exiting");
                Ok(true)
            }
            signo => {
                panic!("Caught an impossible signal {:?}", signo);
            }
        },
        // No signals waiting (SFD_NONBLOCK flag is set)
        Ok(None) => Ok(false),

        Err(err) => Err(err.into()),
    }
}

/// Handle blocking the event loop
fn process_poll(poll_timeout: i32, fds: &mut Vec<libc::pollfd>) -> StratisResult<()> {
    let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };

    // TODO: refine this behavior.
    // Different behaviors may be indicated, depending on the value of
    // errno when return value is -1.
    if r < 0 {
        return Err(StratisError::Error(format!(
            "poll command failed: number of fds: {}, timeout: {}",
            fds.len(),
            poll_timeout
        )));
    }
    Ok(())
}

/// Set up all sorts of signal and event handling mechanisms.
/// Initialize the engine and keep it running until a signal is received
/// or a fatal error is encountered. Dump log entries on specified signal
/// via buff_log.
fn run(matches: &ArgMatches, buff_log: &buff_log::Handle<env_logger::Logger>) -> StratisResult<()> {
    // Ensure that the debug log is output when we leave this function.
    let _guard = buff_log.to_guard();

    let mut dbus_support = MaybeDbusSupport::new();

    // Setup a udev listener before initializing the engine. A device may
    // appear after the engine has processed the udev db, but before it has
    // completed initialization. Unless the udev event has been recorded, the
    // engine will miss the device.
    // This is especially important since stratisd must run during early boot.
    let context = libudev::Context::new()?;
    let mut udev_monitor = UdevMonitor::create(&context)?;

    let engine: Rc<RefCell<dyn Engine>> = {
        info!("stratis daemon version {} started", VERSION);
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are:

    0   == Always udev fd index
    1   == SIGNAL FD index
    2   == engine index if eventable
    2/3 == Start of dbus client file descriptor(s)
            * 2 if engine is not eventable
            * else 3
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_SIGNALFD: usize = 1;
    const FD_INDEX_ENGINE: usize = 2;

    /*
    fds is a Vec of libc::pollfd structs. Ideally, it would be possible
    to use the higher level nix crate to handle polling. If this were possible,
    then the Vec would be one of nix::poll::PollFds and this would be more
    rustic. Unfortunately, the rust D-Bus library requires an explicit file
    descriptor to be passed as an argument to Connection::watch_handle(),
    and the explicit file descriptor can not be extracted from the PollFd
    struct. So, at this time, sticking with libc is less complex than
    converting to using nix, because if using nix, the file descriptor would
    have to be maintained in the Vec as well as the PollFd struct.
    */
    let mut fds = Vec::new();

    fds.push(libc::pollfd {
        fd: udev_monitor.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    // Signals can be queued up on this file descriptor
    let mut sfd = {
        let mut mask = SigSet::empty();
        mask.add(signal::SIGINT);
        mask.add(signal::SIGUSR1);
        mask.thread_block()?;
        SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK)?
    };

    fds.push(libc::pollfd {
        fd: sfd.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    let eventable = engine.borrow().get_eventable();

    if let Some(evt) = eventable {
        fds.push(libc::pollfd {
            fd: evt.get_pollable_fd(),
            revents: 0,
            events: libc::POLLIN,
        });
    };

    let dbus_client_index_start = if eventable.is_some() {
        FD_INDEX_ENGINE + 1
    } else {
        FD_INDEX_ENGINE
    };

    loop {
        if fds[FD_INDEX_UDEV].revents != 0 {
            udev_monitor.handle_events(&mut *engine.borrow_mut(), &mut dbus_support)
        }

        if fds[FD_INDEX_SIGNALFD].revents != 0 {
            match process_signal(&mut sfd, buff_log) {
                Ok(should_exit) => {
                    if should_exit {
                        return Ok(());
                    }
                }
                Err(e) => return Err(e),
            }
        }

        if let Some(evt) = eventable {
            if fds[FD_INDEX_ENGINE].revents != 0 {
                evt.clear_event()?;
                engine.borrow_mut().evented()?;
            }
        }

        dbus_support.process(&engine, &mut fds, dbus_client_index_start);

        process_poll(dbus_support.poll_timeout(), &mut fds)?;
    }
}

fn main() {
    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(
            Arg::with_name("debug")
                .long("debug")
                .help("Print additional output for debugging"),
        )
        .arg(
            Arg::with_name("sim")
                .long("sim")
                .help("Use simulator engine"),
        )
        .get_matches();

    // Using a let-expression here so that the scope of the lock file
    // is the rest of the block.
    let lock_file = trylock_pid_file();

    let result = {
        match lock_file {
            Err(err) => Err(err),
            Ok(_) => {
                let log_handle = initialize_log(matches.is_present("debug"));
                run(&matches, &log_handle)
            }
        }
    };

    if let Err(err) = result {
        eprintln!("{}", err);
        exit(1);
    } else {
        exit(0);
    }
}
<commit_msg>Do not return IO error if PID file is unreadable<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/.

#![allow(clippy::doc_markdown)]

#[macro_use]
extern crate log;

use std::{
    cell::RefCell,
    env,
    fs::{File, OpenOptions},
    io::{Read, Write},
    os::unix::io::{AsRawFd, RawFd},
    process::exit,
    rc::Rc,
};

use chrono::Duration;
use clap::{App, Arg, ArgMatches};
use env_logger::Builder;
use log::LevelFilter;
use nix::{
    fcntl::{flock, FlockArg},
    sys::{
        signal::{self, SigSet},
        signalfd::{SfdFlags, SignalFd},
    },
    unistd::getpid,
};
use uuid::Uuid;

#[cfg(feature = "dbus_enabled")]
use libstratis::{
    dbus_api::{DbusConnectionData, EventHandler},
    engine::get_engine_listener_list_mut,
};

use libstratis::{
    engine::{Engine, Pool, SimEngine, StratEngine},
    stratis::{buff_log, StratisError, StratisResult, VERSION},
};

const STRATISD_PID_PATH: &str = "/run/stratisd.pid";

/// Number of minutes to buffer log entries.
const DEFAULT_LOG_HOLD_MINUTES: i64 = 30;

/// Configure the env_logger as necessary in order to allow the buffered
/// logger to work correctly. Return a Handle to the underlying env_logger.
pub fn from_env_logger(
    mut builder: env_logger::Builder,
    pass_through: bool,
    hold_time: Option<Duration>,
) -> buff_log::Handle<env_logger::Logger> {
    // Do not have the env_logger set the timestamp. Because the entries are
    // buffered, the timestamp set by the env_logger will correspond to the
    // time at which the entry was dumped, not the time of its origination.
    builder.default_format_timestamp(false);
    buff_log::Logger::new(builder.build(), pass_through, hold_time).init()
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> buff_log::Handle<env_logger::Logger> {
    let mut builder = Builder::new();
    if debug {
        builder.filter(Some("stratisd"), LevelFilter::Debug);
        builder.filter(Some("libstratis"), LevelFilter::Debug);
        from_env_logger(builder, true, None)
    } else {
        builder.filter_level(LevelFilter::Trace);
        if let Ok(s) = env::var("RUST_LOG") {
            builder.parse(&s);
        }
        from_env_logger(
            builder,
            false,
            Some(Duration::minutes(DEFAULT_LOG_HOLD_MINUTES)),
        )
    }
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn trylock_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)
        .map_err(|err| {
            StratisError::Error(format!(
                "Failed to create or open the stratisd PID file at {}: {}",
                STRATISD_PID_PATH, err
            ))
        })?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write_all(getpid().to_string().as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();

            if f.read_to_string(&mut buf).is_err() {
                buf = "<unreadable>".to_string();
            }

            Err(StratisError::Error(format!(
                "Daemon already running with supposed pid: {}",
                buf
            )))
        }
    }
}

// Conditionally compiled support for a D-Bus interface.
struct MaybeDbusSupport {
    #[cfg(feature = "dbus_enabled")]
    handle: Option<libstratis::dbus_api::DbusConnectionData>,
}

// If D-Bus compiled out, do very little.
#[cfg(not(feature = "dbus_enabled"))]
impl MaybeDbusSupport {
    fn new() -> MaybeDbusSupport {
        MaybeDbusSupport {}
    }

    fn process(
        &mut self,
        _engine: &Rc<RefCell<dyn Engine>>,
        _fds: &mut Vec<libc::pollfd>,
        _dbus_client_index_start: usize,
    ) {
    }

    fn register_pool(&mut self, _pool_uuid: Uuid, _pool: &mut dyn Pool) {}

    fn poll_timeout(&self) -> i32 {
        // Non-DBus timeout is infinite
        -1
    }
}

#[cfg(feature = "dbus_enabled")]
impl MaybeDbusSupport {
    fn new() -> MaybeDbusSupport {
        MaybeDbusSupport { handle: None }
    }

    /// Connect to D-Bus and register pools, if not already connected.
    /// Return the connection, if made or already existing, otherwise, None.
    fn setup_connection(
        &mut self,
        engine: &Rc<RefCell<dyn Engine>>,
    ) -> Option<&mut DbusConnectionData> {
        if self.handle.is_none() {
            match libstratis::dbus_api::DbusConnectionData::connect(Rc::clone(engine)) {
                Err(err) => {
                    warn!("D-Bus API is not available: {}", err);
                }
                Ok(mut handle) => {
                    info!("D-Bus API is available");
                    let event_handler = Box::new(EventHandler::new(Rc::clone(&handle.connection)));
                    get_engine_listener_list_mut().register_listener(event_handler);
                    // Register all the pools with dbus
                    for (_, pool_uuid, pool) in engine.borrow_mut().pools_mut() {
                        handle.register_pool(pool_uuid, pool)
                    }
                    self.handle = Some(handle);
                }
            }
        };
        self.handle.as_mut()
    }

    /// Handle any client dbus requests.
    fn process(
        &mut self,
        engine: &Rc<RefCell<dyn Engine>>,
        fds: &mut Vec<libc::pollfd>,
        dbus_client_index_start: usize,
    ) {
        if let Some(handle) = self.setup_connection(engine) {
            handle.handle(&fds[dbus_client_index_start..]);

            // Refresh list of dbus fds to poll for. This can change as
            // D-Bus clients come and go.
            fds.truncate(dbus_client_index_start);
            fds.extend(
                handle
                    .connection
                    .borrow()
                    .watch_fds()
                    .iter()
                    .map(|w| w.to_pollfd()),
            );
        }
    }

    fn register_pool(&mut self, pool_uuid: Uuid, pool: &mut dyn Pool) {
        if let Some(h) = self.handle.as_mut() {
            h.register_pool(pool_uuid, pool)
        }
    }

    fn poll_timeout(&self) -> i32 {
        // If there is no D-Bus connection set timeout to 1 sec (1000 ms), so
        // that stratisd can periodically attempt to set up a connection.
        // If the connection is up, set the timeout to infinite; there is no
        // need to poll as events will be received.
        self.handle.as_ref().map_or(1000, |_| -1)
    }
}

// A facility for listening for and handling udev events that stratisd
// considers interesting.
struct UdevMonitor<'a> {
    socket: libudev::MonitorSocket<'a>,
}

impl<'a> UdevMonitor<'a> {
    fn create(context: &'a libudev::Context) -> StratisResult<UdevMonitor<'a>> {
        let mut monitor = libudev::Monitor::new(context)?;
        monitor.match_subsystem("block")?;

        Ok(UdevMonitor {
            socket: monitor.listen()?,
        })
    }

    fn as_raw_fd(&mut self) -> RawFd {
        self.socket.as_raw_fd()
    }

    /// Handle udev events.
    /// Check if a pool can be constructed and update engine and D-Bus layer
    /// data structures if so.
    fn handle_events(&mut self, engine: &mut dyn Engine, dbus_support: &mut MaybeDbusSupport) {
        while let Some(event) = self.socket.receive_event() {
            if let Some((pool_uuid, pool)) = engine.handle_event(&event) {
                dbus_support.register_pool(pool_uuid, pool);
            }
        }
    }
}

// Process any pending signals, return true if SIGINT received.
// Return an error if there was an error reading the signal.
fn process_signal(
    sfd: &mut SignalFd,
    buff_log: &buff_log::Handle<env_logger::Logger>,
) -> StratisResult<bool> {
    match sfd.read_signal() {
        // This is an unsafe conversion, but in this context that is
        // mostly harmless. A negative converted value, which is
        // virtually impossible, will not match any of the masked
        // values, and stratisd will panic and exit.
        Ok(Some(sig)) => match sig.ssi_signo as i32 {
            nix::libc::SIGUSR1 => {
                info!(
                    "SIGUSR1 received, dumping {} buffered log entries",
                    buff_log.buffered_count()
                );
                buff_log.dump();
                Ok(false)
            }
            nix::libc::SIGINT => {
                info!("SIGINT received, exiting");
                Ok(true)
            }
            signo => {
                panic!("Caught an impossible signal {:?}", signo);
            }
        },
        // No signals waiting (SFD_NONBLOCK flag is set)
        Ok(None) => Ok(false),

        Err(err) => Err(err.into()),
    }
}

/// Handle blocking the event loop
fn process_poll(poll_timeout: i32, fds: &mut Vec<libc::pollfd>) -> StratisResult<()> {
    let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };

    // TODO: refine this behavior.
    // Different behaviors may be indicated, depending on the value of
    // errno when return value is -1.
    if r < 0 {
        return Err(StratisError::Error(format!(
            "poll command failed: number of fds: {}, timeout: {}",
            fds.len(),
            poll_timeout
        )));
    }
    Ok(())
}

/// Set up all sorts of signal and event handling mechanisms.
/// Initialize the engine and keep it running until a signal is received
/// or a fatal error is encountered. Dump log entries on specified signal
/// via buff_log.
fn run(matches: &ArgMatches, buff_log: &buff_log::Handle<env_logger::Logger>) -> StratisResult<()> {
    // Ensure that the debug log is output when we leave this function.
    let _guard = buff_log.to_guard();

    let mut dbus_support = MaybeDbusSupport::new();

    // Setup a udev listener before initializing the engine. A device may
    // appear after the engine has processed the udev db, but before it has
    // completed initialization. Unless the udev event has been recorded, the
    // engine will miss the device.
    // This is especially important since stratisd must run during early boot.
    let context = libudev::Context::new()?;
    let mut udev_monitor = UdevMonitor::create(&context)?;

    let engine: Rc<RefCell<dyn Engine>> = {
        info!("stratis daemon version {} started", VERSION);
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are:

    0   == Always udev fd index
    1   == SIGNAL FD index
    2   == engine index if eventable
    2/3 == Start of dbus client file descriptor(s)
            * 2 if engine is not eventable
            * else 3
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_SIGNALFD: usize = 1;
    const FD_INDEX_ENGINE: usize = 2;

    /*
    fds is a Vec of libc::pollfd structs. Ideally, it would be possible
    to use the higher level nix crate to handle polling. If this were possible,
    then the Vec would be one of nix::poll::PollFds and this would be more
    rustic. Unfortunately, the rust D-Bus library requires an explicit file
    descriptor to be passed as an argument to Connection::watch_handle(),
    and the explicit file descriptor can not be extracted from the PollFd
    struct. So, at this time, sticking with libc is less complex than
    converting to using nix, because if using nix, the file descriptor would
    have to be maintained in the Vec as well as the PollFd struct.
    */
    let mut fds = Vec::new();

    fds.push(libc::pollfd {
        fd: udev_monitor.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    // Signals can be queued up on this file descriptor
    let mut sfd = {
        let mut mask = SigSet::empty();
        mask.add(signal::SIGINT);
        mask.add(signal::SIGUSR1);
        mask.thread_block()?;
        SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK)?
    };

    fds.push(libc::pollfd {
        fd: sfd.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    let eventable = engine.borrow().get_eventable();

    if let Some(evt) = eventable {
        fds.push(libc::pollfd {
            fd: evt.get_pollable_fd(),
            revents: 0,
            events: libc::POLLIN,
        });
    };

    let dbus_client_index_start = if eventable.is_some() {
        FD_INDEX_ENGINE + 1
    } else {
        FD_INDEX_ENGINE
    };

    loop {
        if fds[FD_INDEX_UDEV].revents != 0 {
            udev_monitor.handle_events(&mut *engine.borrow_mut(), &mut dbus_support)
        }

        if fds[FD_INDEX_SIGNALFD].revents != 0 {
            match process_signal(&mut sfd, buff_log) {
                Ok(should_exit) => {
                    if should_exit {
                        return Ok(());
                    }
                }
                Err(e) => return Err(e),
            }
        }

        if let Some(evt) = eventable {
            if fds[FD_INDEX_ENGINE].revents != 0 {
                evt.clear_event()?;
                engine.borrow_mut().evented()?;
            }
        }

        dbus_support.process(&engine, &mut fds, dbus_client_index_start);

        process_poll(dbus_support.poll_timeout(), &mut fds)?;
    }
}

fn main() {
    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(
            Arg::with_name("debug")
                .long("debug")
                .help("Print additional output for debugging"),
        )
        .arg(
            Arg::with_name("sim")
                .long("sim")
                .help("Use simulator engine"),
        )
        .get_matches();

    // Using a let-expression here so that the scope of the lock file
    // is the rest of the block.
    let lock_file = trylock_pid_file();

    let result = {
        match lock_file {
            Err(err) => Err(err),
            Ok(_) => {
                let log_handle = initialize_log(matches.is_present("debug"));
                run(&matches, &log_handle)
            }
        }
    };

    if let Err(err) = result {
        eprintln!("{}", err);
        exit(1);
    } else {
        exit(0);
    }
}
<|endoftext|>


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

use binding::thread;
use types::Value;

#[cfg(unix)]
use types::RawFd;

use {Class, Object, VerifiedObject};

/// `Thread`
#[derive(Debug, PartialEq)]
pub struct Thread {
    value: Value,
}

impl Thread {
    /// Creates a new green thread.
    ///
    /// The returning value of the closure will be available as `#value` of the thread
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Fixnum, Thread, VM};
    /// # VM::init();
    ///
    /// Thread::new(|| {
    ///     let computation_result = 1 + 2;
    ///
    ///     Fixnum::new(computation_result)
    /// });
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// Thread.new do
    ///   computation_result = 1 + 2
    ///
    ///   computation_result
    /// end
    /// ```
    pub fn new<F, R>(func: F) -> Self
        where F: FnOnce() -> R,
              R: Object
    {
        Self::from(thread::create(func))
    }

    /// Tells scheduler to switch to other threads while current thread is waiting for a
    /// readable event on the given file descriptor.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use ruru::{Thread, VM};
    /// # VM::init();
    ///
    /// // let fd = ...;
    ///
    /// Thread::wait_fd(fd);
    /// ```
    #[cfg(unix)]
    pub fn wait_fd(fd: RawFd) {
        thread::wait_fd(fd);
    }

    /// Release GVL for current thread.
    ///
    /// **Warning!** Due to MRI limitations, interaction with Ruby objects is not allowed while
    /// GVL is released, it may cause unexpected behaviour.
    /// [Read more at Ruby documentation](https://github.com/ruby/ruby/blob/2fc5210f31ad23463d7b0a0e36bcfbeee7b41b3e/thread.c#L1314-L1398)
    ///
    /// You should extract all the information from Ruby world before invoking
    /// `thread_call_without_gvl`.
    ///
    /// GVL will be re-acquired when the closure is finished.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// #[macro_use] extern crate ruru;
    ///
    /// use ruru::{Class, Fixnum, Object, Thread};
    ///
    /// class!(Calculator);
    ///
    /// methods!(
    ///     Calculator,
    ///     itself,
    ///
    ///     fn heavy_computation() -> Fixnum {
    ///         let computation = || { 2 * 2 };
    ///         let unblocking_function = || {};
    ///
    ///         // release GVL for current thread until `computation` is completed
    ///         let result = Thread::call_without_gvl(
    ///             computation,
    ///             Some(unblocking_function)
    ///         );
    ///
    ///         // GVL is re-acquired, we can interact with Ruby-world
    ///         Fixnum::new(result)
    ///     }
    /// );
    ///
    /// fn main() {
    ///     Class::new("Calculator", None).define(|itself| {
    ///         itself.def("heavy_computation", heavy_computation);
    ///     });
    /// }
    /// ```
    pub fn call_without_gvl<F, R, G>(func: F, unblock_func: Option<G>) -> R
        where F: FnOnce() -> R,
              G: FnOnce()
    {
        thread::call_without_gvl(func, unblock_func)
    }

    pub fn call_without_gvl2<F, R, G>(func: F, unblock_func: Option<G>) -> R
        where F: FnOnce() -> R,
              G: FnOnce()
    {
        thread::call_without_gvl2(func, unblock_func)
    }

    pub fn call_with_gvl<F, R>(func: F) -> R
        where F: FnOnce() -> R
    {
        thread::call_with_gvl(func)
    }
}

impl From<Value> for Thread {
    fn from(value: Value) -> Self {
        Thread { value: value }
    }
}

impl Object for Thread {
    #[inline]
    fn value(&self) -> Value {
        self.value
    }
}

impl VerifiedObject for Thread {
    fn is_correct_type<T: Object>(object: &T) -> bool {
        object.class() == Class::from_existing("Thread")
    }

    fn error_message() -> &'static str {
        "Error converting to Thread"
    }
}
<commit_msg>Add a doctest for Thread::wait_fd()<commit_after>use std::convert::From;

use binding::thread;
use types::Value;

#[cfg(unix)]
use types::RawFd;

use {Class, Object, VerifiedObject};

/// `Thread`
#[derive(Debug, PartialEq)]
pub struct Thread {
    value: Value,
}

impl Thread {
    /// Creates a new green thread.
    ///
    /// The returning value of the closure will be available as `#value` of the thread
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Fixnum, Thread, VM};
    /// # VM::init();
    ///
    /// Thread::new(|| {
    ///     let computation_result = 1 + 2;
    ///
    ///     Fixnum::new(computation_result)
    /// });
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// Thread.new do
    ///   computation_result = 1 + 2
    ///
    ///   computation_result
    /// end
    /// ```
    pub fn new<F, R>(func: F) -> Self
        where F: FnOnce() -> R,
              R: Object
    {
        Self::from(thread::create(func))
    }

    /// Tells scheduler to switch to other threads while current thread is waiting for a
    /// readable event on the given file descriptor.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::os::unix::io::AsRawFd;
    /// use std::os::unix::net::UnixStream;
    ///
    /// use ruru::{Thread, VM};
    /// # VM::init();
    ///
    /// let (unix_socket, _) = UnixStream::pair().unwrap();
    ///
    /// Thread::wait_fd(unix_socket.as_raw_fd());
    /// ```
    #[cfg(unix)]
    pub fn wait_fd(fd: RawFd) {
        thread::wait_fd(fd);
    }

    /// Release GVL for current thread.
    ///
    /// **Warning!** Due to MRI limitations, interaction with Ruby objects is not allowed while
    /// GVL is released, it may cause unexpected behaviour.
    /// [Read more at Ruby documentation](https://github.com/ruby/ruby/blob/2fc5210f31ad23463d7b0a0e36bcfbeee7b41b3e/thread.c#L1314-L1398)
    ///
    /// You should extract all the information from Ruby world before invoking
    /// `thread_call_without_gvl`.
    ///
    /// GVL will be re-acquired when the closure is finished.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// #[macro_use] extern crate ruru;
    ///
    /// use ruru::{Class, Fixnum, Object, Thread};
    ///
    /// class!(Calculator);
    ///
    /// methods!(
    ///     Calculator,
    ///     itself,
    ///
    ///     fn heavy_computation() -> Fixnum {
    ///         let computation = || { 2 * 2 };
    ///         let unblocking_function = || {};
    ///
    ///         // release GVL for current thread until `computation` is completed
    ///         let result = Thread::call_without_gvl(
    ///             computation,
    ///             Some(unblocking_function)
    ///         );
    ///
    ///         // GVL is re-acquired, we can interact with Ruby-world
    ///         Fixnum::new(result)
    ///     }
    /// );
    ///
    /// fn main() {
    ///     Class::new("Calculator", None).define(|itself| {
    ///         itself.def("heavy_computation", heavy_computation);
    ///     });
    /// }
    /// ```
    pub fn call_without_gvl<F, R, G>(func: F, unblock_func: Option<G>) -> R
        where F: FnOnce() -> R,
              G: FnOnce()
    {
        thread::call_without_gvl(func, unblock_func)
    }

    pub fn call_without_gvl2<F, R, G>(func: F, unblock_func: Option<G>) -> R
        where F: FnOnce() -> R,
              G: FnOnce()
    {
        thread::call_without_gvl2(func, unblock_func)
    }

    pub fn call_with_gvl<F, R>(func: F) -> R
        where F: FnOnce() -> R
    {
        thread::call_with_gvl(func)
    }
}

impl From<Value> for Thread {
    fn from(value: Value) -> Self {
        Thread { value: value }
    }
}

impl Object for Thread {
    #[inline]
    fn value(&self) -> Value {
        self.value
    }
}

impl VerifiedObject for Thread {
    fn is_correct_type<T: Object>(object: &T) -> bool {
        object.class() == Class::from_existing("Thread")
    }

    fn error_message() -> &'static str {
        "Error converting to Thread"
    }
}
<|endoftext|>


<commit_before>use super::{
    Encodable,
    SszStream
};
use super::ethereum_types::{ H256, U256 };

/*
 * Note: there is a "to_bytes" function for integers
 * in Rust nightly. When it is in stable, we should
 * use it instead.
 */
macro_rules! impl_encodable_for_uint {
    ($type: ident) => {
        impl Encodable for $type {
            fn ssz_append(&self, s: &mut SszStream)
            {
                // Number of bits required to represent this integer.
                // This could be optimised at the expense of complexity.
                let num_bits = {
                    let mut n = *self;
                    let mut r: usize = 0;
                    while n > 0 {
                        n >>= 1;
                        r += 1;
                    }
                    if r == 0 { 1 } else { r }
                };
                // Number of bytes required to represent this bit
                let num_bytes = (num_bits + 8 - 1) / 8;
                let mut ssz_val: Vec<u8> = Vec::with_capacity(num_bytes);
                ssz_val.resize(num_bytes, 0);
                for i in (0..num_bytes).rev() {
                    let offset = (num_bytes - i - 1) * 8;
                    ssz_val[i] = 0_u8 | (self >> offset) as u8
                }
                s.append_encoded_val(&ssz_val);
            }
        }
    }
}

impl_encodable_for_uint!(u8);
impl_encodable_for_uint!(u16);
impl_encodable_for_uint!(u32);
impl_encodable_for_uint!(u64);

impl Encodable for H256 {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_encoded_val(&self.to_vec());
    }
}

impl Encodable for U256 {
    fn ssz_append(&self, s: &mut SszStream) {
        let mut a = [0; 32];
        self.to_big_endian(&mut a);
        s.append_encoded_val(&a.to_vec());
    }
}

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

    #[test]
    fn test_ssz_encode_u8() {
        let x: u16 = 0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 0]);

        let x: u16 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u16 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u16 = 255;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 255]);
    }

    #[test]
    fn test_ssz_encode_u16() {
        let x: u16 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u16 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u16 = 1 << 8;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 2, 1, 0]);

        let x: u16 = 65535;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 2, 255, 255]);
    }

    #[test]
    fn test_ssz_encode_u32() {
        let x: u32 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u32 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u32 = 1 << 16;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 3, 1, 0, 0]);

        let x: u32 = 1 << 24;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 4, 1, 0, 0, 0]);

        let x: u32 = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 4, 255, 255, 255, 255]);
    }

    #[test]
    fn test_ssz_encode_u64() {
        let x: u64 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u64 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u64 = 1 << 32;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 5, 1, 0, 0, 0, 0]);

        let x: u64 = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]);
    }
}
<commit_msg>Add ssz Encodable trait for usize<commit_after>use super::{
    Encodable,
    SszStream
};
use super::ethereum_types::{ H256, U256 };

/*
 * Note: there is a "to_bytes" function for integers
 * in Rust nightly. When it is in stable, we should
 * use it instead.
 */
macro_rules! impl_encodable_for_uint {
    ($type: ident) => {
        impl Encodable for $type {
            fn ssz_append(&self, s: &mut SszStream)
            {
                // Number of bits required to represent this integer.
                // This could be optimised at the expense of complexity.
                let num_bits = {
                    let mut n = *self;
                    let mut r: usize = 0;
                    while n > 0 {
                        n >>= 1;
                        r += 1;
                    }
                    if r == 0 { 1 } else { r }
                };
                // Number of bytes required to represent this bit
                let num_bytes = (num_bits + 8 - 1) / 8;
                let mut ssz_val: Vec<u8> = Vec::with_capacity(num_bytes);
                ssz_val.resize(num_bytes, 0);
                for i in (0..num_bytes).rev() {
                    let offset = (num_bytes - i - 1) * 8;
                    ssz_val[i] = 0_u8 | (self >> offset) as u8
                }
                s.append_encoded_val(&ssz_val);
            }
        }
    }
}

impl_encodable_for_uint!(u8);
impl_encodable_for_uint!(u16);
impl_encodable_for_uint!(u32);
impl_encodable_for_uint!(u64);
impl_encodable_for_uint!(usize);

impl Encodable for H256 {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_encoded_val(&self.to_vec());
    }
}

impl Encodable for U256 {
    fn ssz_append(&self, s: &mut SszStream) {
        let mut a = [0; 32];
        self.to_big_endian(&mut a);
        s.append_encoded_val(&a.to_vec());
    }
}

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

    #[test]
    fn test_ssz_encode_u8() {
        let x: u16 = 0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 0]);

        let x: u16 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u16 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u16 = 255;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 255]);
    }

    #[test]
    fn test_ssz_encode_u16() {
        let x: u16 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u16 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u16 = 1 << 8;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 2, 1, 0]);

        let x: u16 = 65535;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 2, 255, 255]);
    }

    #[test]
    fn test_ssz_encode_u32() {
        let x: u32 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u32 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u32 = 1 << 16;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 3, 1, 0, 0]);

        let x: u32 = 1 << 24;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 4, 1, 0, 0, 0]);

        let x: u32 = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 4, 255, 255, 255, 255]);
    }

    #[test]
    fn test_ssz_encode_u64() {
        let x: u64 = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: u64 = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: u64 = 1 << 32;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 5, 1, 0, 0, 0, 0]);

        let x: u64 = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]);
    }

    #[test]
    fn test_ssz_encode_usize() {
        let x: usize = 1;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 1]);

        let x: usize = 100;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 1, 100]);

        let x: usize = 1 << 32;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 5, 1, 0, 0, 0, 0]);

        let x: usize = !0;
        let mut ssz = SszStream::new();
        ssz.append(&x);
        assert_eq!(ssz.drain(), vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]);
    }
}
<|endoftext|>


<commit_before>extern crate mio;
extern crate byteorder;

use std::io::Cursor;
use std::mem;
use mio::{ Handler, EventLoop, Token, EventSet };
use mio::util::Slab;
use mio::tcp::TcpStream;
use super::{ ConnectionMessage, ConnectionHandler };
use ::sync::Sender;

//The main io loop for clients to interact with
pub struct ConnectionManager {
	connections: Slab<Connection>
}

impl ConnectionManager {
	pub fn new() -> ConnectionManager {
		ConnectionManager {
			connections: Slab::new(1)
		}
	}
}

impl ConnectionHandler for ConnectionManager {
	fn request(&mut self, handle: Sender, bytes: Vec<u8>) {
		//Find an available, compatible connection
		//Store the sender against the connections token id
		//Store the message with the connections token id
	}

	fn execute(&mut self, bytes: Vec<u8>) {
		//Find an available, compatible connection
		//Store the message with the connections token id
	}
}

impl Handler for ConnectionManager {
	type Timeout = ();
	type Message = ConnectionMessage;

	fn notify(&mut self, event_loop: &mut EventLoop<ConnectionManager>, msg: Self::Message) {
		match msg {
			ConnectionMessage::Request(sender, bytes) => {
				self.request(sender, bytes);
			},
			ConnectionMessage::Execute(bytes) => {
				self.execute(bytes);
			},
			ConnectionMessage::Response(bytes) => {
				//Find a saved sender by token id
				//If found, push bytes down channel
				//If not found, ignore and move on
				panic!("implement")
			}
		}
	}

	fn ready(&mut self, event_loop: &mut EventLoop<ConnectionManager>, token: Token, events: EventSet) {
		//Get a connection ready, or deal with closing
		panic!("implement")
	}
}

//A single tcp connection to a broker endpoint
struct Connection {
	socket: TcpStream,
	token: Token,
	state: ConnectionState
}

enum ConnectionState {
	Reading(Option<Sender>, Vec<u8>),
	ReadingMessage(Option<Sender>, u32, Vec<u8>),
	Writing(Option<Sender>, Cursor<Vec<u8>>),
	Closed
}<commit_msg>Update io_loop.rs<commit_after>extern crate mio;
extern crate byteorder;

use std::io::Cursor;
use std::mem;
use mio::{ Handler, EventLoop, Token, EventSet };
use mio::util::Slab;
use mio::tcp::TcpStream;
use super::{ ConnectionMessage, ConnectionHandler };
use ::sync::Sender;

//TODO: We need to be able to easily specify our own event loop implementations (such as handling messages directly) as opposed to threading. Conn API needs to be useful in its own right

//The main io loop for clients to interact with
pub struct ConnectionManager {
	connections: Slab<Connection>
}

impl ConnectionManager {
	pub fn new() -> ConnectionManager {
		ConnectionManager {
			connections: Slab::new(1)
		}
	}
}

impl ConnectionHandler for ConnectionManager {
	fn request(&mut self, handle: Sender, bytes: Vec<u8>) {
		//Find an available, compatible connection
		//Store the sender against the connections token id
		//Store the message with the connections token id
	}

	fn execute(&mut self, bytes: Vec<u8>) {
		//Find an available, compatible connection
		//Store the message with the connections token id
	}
}

impl Handler for ConnectionManager {
	type Timeout = ();
	type Message = ConnectionMessage;

	fn notify(&mut self, event_loop: &mut EventLoop<ConnectionManager>, msg: Self::Message) {
		match msg {
			ConnectionMessage::Request(sender, bytes) => {
				self.request(sender, bytes);
			},
			ConnectionMessage::Execute(bytes) => {
				self.execute(bytes);
			},
			ConnectionMessage::Response(bytes) => {
				//Find a saved sender by token id
				//If found, push bytes down channel
				//If not found, ignore and move on
				panic!("implement")
			}
		}
	}

	fn ready(&mut self, event_loop: &mut EventLoop<ConnectionManager>, token: Token, events: EventSet) {
		//Get a connection ready, or deal with closing
		panic!("implement")
	}
}

//A single tcp connection to a broker endpoint
struct Connection {
	socket: TcpStream,
	token: Token,
	state: ConnectionState
}

enum ConnectionState {
	Reading(Option<Sender>, Vec<u8>),
	ReadingMessage(Option<Sender>, u32, Vec<u8>),
	Writing(Option<Sender>, Cursor<Vec<u8>>),
	Closed
}
<|endoftext|>


<commit_before>use nom_lua53;
use nom_lua53::Statement;
use nom_lua53::RepeatBlock;
use nom_lua53::stat_expr_types::Block;
use types::LuaState;
use expression;
use std;
use super::{Result, var_to_string};
use super::types::LuaValue;

#[derive(PartialEq)]
pub enum FlowControl {
    None,
    Return(Vec<LuaValue>),
    Break,
}

pub fn exec_statement(stmt: &Statement, ctx: &mut LuaState) -> Result<FlowControl> {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals
                .as_ref()
                .expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                let local_scope = ctx.get_mutable_local_scope().unwrap();
                local_scope.set_string(var_to_string(var), &computed_value.unwrap());
            };
            Ok(FlowControl::None)
        }
        &Statement::Assignment(ref ass) => {
            let mut values = Vec::with_capacity(ass.vals.len());
            for exp in ass.vals.iter() {
                values.push(expression::eval_expr(&exp, &ctx)?);
            }

            for (prefexp, val) in ass.vars.iter().zip(values.drain(..)) {
                let assignment = expression::prefixexp::resolve_prefix_expr(
                    &prefexp.prefix,
                    &prefexp.suffix_chain,
                    ctx,
                )?;
                assignment.environment.set(&assignment.index, &val)?;
            }
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
            Ok(FlowControl::None)
        }
        &Statement::Semicolon => {
            Ok(FlowControl::None)
        }
        &Statement::Ite(ref ite) => {
            exec_if_then_else(ite, ctx)
        }
        &Statement::While(ref blk) => {
            exec_while(blk, ctx)
        }
        &Statement::Repeat(ref blk) => {
            exec_repeat(blk, ctx)
        }
        &Statement::Break => Ok(FlowControl::Break),
        _ => {Ok(FlowControl::None)}
    }
}

pub fn exec_block(block: &Block, ctx: &mut LuaState) -> Result<FlowControl> {
    ctx.push_scope();
    let mut ret = FlowControl::None;
    for stmt in block.stmts.iter() {
        match exec_statement(&stmt, ctx)? {
            FlowControl::Break => { ret =  FlowControl::Break; break },
            FlowControl::Return(val) => { ret = FlowControl::Return(val); break },
            FlowControl::None => {}
        }
    };

    if ret != FlowControl::None {
        if let Some(ref expressions) = block.ret_stmt {
            let mut results = std::vec::Vec::with_capacity(expressions.len());
            for exp in expressions {
                results.push(expression::eval_expr(exp, ctx)?)
            }
            ret = FlowControl::Return(results)
        }
    }

    ctx.pop_scope();
    Ok(ret)
}

pub fn exec_if_then_else(ite: &nom_lua53::IfThenElse, ctx: &mut LuaState) -> Result<FlowControl> {
    if expression::boolean_coercion(&expression::eval_expr(&ite.cond, ctx)?) {
        exec_block(&ite.then_blk, ctx)
    } else {
        match ite.elseifs.iter().fold(None,
         |current, &(ref exp, ref block)|
          if current.is_none() {
              match expression::eval_expr(&exp, ctx) {
                  Ok(_) => Some(exec_block(&block, ctx)),
                  Err(err) => Some(Err(err))
              }
          } else { current }) {
              Some(val) => val,
              None => match &ite.else_blk {
                  &Some(ref blk) => exec_block(blk, ctx),
                  &None => Ok(FlowControl::None)
              }
          }
    }
}

pub fn exec_while(blk: &nom_lua53::WhileBlock, ctx: &mut LuaState) -> Result<FlowControl> {
    while expression::boolean_coercion(&expression::eval_expr(&blk.cond, ctx)?) {
        let disrupt = exec_block(&blk.block, ctx)?;
        match disrupt {
            FlowControl::Return(val) => {
                return Ok(FlowControl::Return(val))
            }
            FlowControl::Break => {
                return Ok(FlowControl::None)
            }
            FlowControl::None => {}
        }
    }
    return Ok(FlowControl::None)
}

pub fn exec_repeat(blk: &RepeatBlock, ctx: &mut LuaState) -> Result<FlowControl> {
    let mut ret = FlowControl::None;
    loop {
        ctx.push_scope();
        for stmt in blk.block.stmts.iter() {
            match exec_statement(&stmt, ctx)? {
                FlowControl::Break => { ret =  FlowControl::Break; break },
                FlowControl::Return(val) => { ret = FlowControl::Return(val); break },
                FlowControl::None => {}
            }
        };
        if ret != FlowControl::None {
            if let Some(ref expressions) = blk.block.ret_stmt {
                let mut results = std::vec::Vec::with_capacity(expressions.len());
                for exp in expressions {
                    results.push(expression::eval_expr(exp, ctx)?)
                }
                ret = FlowControl::Return(results);
            }
        }
        if ret != FlowControl::None || expression::boolean_coercion(&expression::eval_expr(&blk.cond, ctx)?) {
            ctx.pop_scope();
            break
        }
        ctx.pop_scope();
    };
    Ok(ret)
}<commit_msg>Add support for pure syntactic blocks<commit_after>use nom_lua53;
use nom_lua53::Statement;
use nom_lua53::RepeatBlock;
use nom_lua53::stat_expr_types::Block;
use types::LuaState;
use expression;
use std;
use super::{Result, var_to_string};
use super::types::LuaValue;

#[derive(PartialEq)]
pub enum FlowControl {
    None,
    Return(Vec<LuaValue>),
    Break,
}

pub fn exec_statement(stmt: &Statement, ctx: &mut LuaState) -> Result<FlowControl> {
    match stmt {
        &Statement::LVarAssign(ref ass) => {
            let values = ass.vals
                .as_ref()
                .expect("There should be some values. Why isn't there any value?!");
            for (var, val) in ass.vars.iter().zip(values.iter()) {
                let computed_value = expression::eval_expr(val, &ctx);
                let local_scope = ctx.get_mutable_local_scope().unwrap();
                local_scope.set_string(var_to_string(var), &computed_value.unwrap());
            };
            Ok(FlowControl::None)
        }
        &Statement::Assignment(ref ass) => {
            let mut values = Vec::with_capacity(ass.vals.len());
            for exp in ass.vals.iter() {
                values.push(expression::eval_expr(&exp, &ctx)?);
            }

            for (prefexp, val) in ass.vars.iter().zip(values.drain(..)) {
                let assignment = expression::prefixexp::resolve_prefix_expr(
                    &prefexp.prefix,
                    &prefexp.suffix_chain,
                    ctx,
                )?;
                assignment.environment.set(&assignment.index, &val)?;
            }
            println!("Assigning {:?} to {:?}", ass.vals, ass.vars);
            Ok(FlowControl::None)
        }
        &Statement::Semicolon => {
            Ok(FlowControl::None)
        }
        &Statement::Ite(ref ite) => {
            exec_if_then_else(ite, ctx)
        }
        &Statement::While(ref blk) => {
            exec_while(blk, ctx)
        }
        &Statement::Repeat(ref blk) => {
            exec_repeat(blk, ctx)
        }
        &Statement::Do(ref blk) => {
            exec_block(blk, ctx)
        }
        &Statement::Break => Ok(FlowControl::Break),
        _ => {Ok(FlowControl::None)}
    }
}

pub fn exec_block(block: &Block, ctx: &mut LuaState) -> Result<FlowControl> {
    ctx.push_scope();
    let mut ret = FlowControl::None;
    for stmt in block.stmts.iter() {
        match exec_statement(&stmt, ctx)? {
            FlowControl::Break => { ret =  FlowControl::Break; break },
            FlowControl::Return(val) => { ret = FlowControl::Return(val); break },
            FlowControl::None => {}
        }
    };

    if ret != FlowControl::None {
        if let Some(ref expressions) = block.ret_stmt {
            let mut results = std::vec::Vec::with_capacity(expressions.len());
            for exp in expressions {
                results.push(expression::eval_expr(exp, ctx)?)
            }
            ret = FlowControl::Return(results)
        }
    }

    ctx.pop_scope();
    Ok(ret)
}

pub fn exec_if_then_else(ite: &nom_lua53::IfThenElse, ctx: &mut LuaState) -> Result<FlowControl> {
    if expression::boolean_coercion(&expression::eval_expr(&ite.cond, ctx)?) {
        exec_block(&ite.then_blk, ctx)
    } else {
        match ite.elseifs.iter().fold(None,
         |current, &(ref exp, ref block)|
          if current.is_none() {
              match expression::eval_expr(&exp, ctx) {
                  Ok(_) => Some(exec_block(&block, ctx)),
                  Err(err) => Some(Err(err))
              }
          } else { current }) {
              Some(val) => val,
              None => match &ite.else_blk {
                  &Some(ref blk) => exec_block(blk, ctx),
                  &None => Ok(FlowControl::None)
              }
          }
    }
}

pub fn exec_while(blk: &nom_lua53::WhileBlock, ctx: &mut LuaState) -> Result<FlowControl> {
    while expression::boolean_coercion(&expression::eval_expr(&blk.cond, ctx)?) {
        let disrupt = exec_block(&blk.block, ctx)?;
        match disrupt {
            FlowControl::Return(val) => {
                return Ok(FlowControl::Return(val))
            }
            FlowControl::Break => {
                return Ok(FlowControl::None)
            }
            FlowControl::None => {}
        }
    }
    return Ok(FlowControl::None)
}

pub fn exec_repeat(blk: &RepeatBlock, ctx: &mut LuaState) -> Result<FlowControl> {
    let mut ret = FlowControl::None;
    loop {
        ctx.push_scope();
        for stmt in blk.block.stmts.iter() {
            match exec_statement(&stmt, ctx)? {
                FlowControl::Break => { ret =  FlowControl::Break; break },
                FlowControl::Return(val) => { ret = FlowControl::Return(val); break },
                FlowControl::None => {}
            }
        };
        if ret != FlowControl::None {
            if let Some(ref expressions) = blk.block.ret_stmt {
                let mut results = std::vec::Vec::with_capacity(expressions.len());
                for exp in expressions {
                    results.push(expression::eval_expr(exp, ctx)?)
                }
                ret = FlowControl::Return(results);
            }
        }
        if ret != FlowControl::None || expression::boolean_coercion(&expression::eval_expr(&blk.cond, ctx)?) {
            ctx.pop_scope();
            break
        }
        ctx.pop_scope();
    };
    Ok(ret)
}<|endoftext|>


<commit_before>//! Types to build operators with general shapes.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use timely_communication::{Push, Pull};

use ::Data;

use progress::nested::subgraph::{Source, Target};
use progress::ChangeBatch;
use progress::{Timestamp, Operate, Antichain};

use progress::frontier::MutableAntichain;

use dataflow::channels::Content;

use dataflow::{Stream, Scope};
use dataflow::channels::pushers::Tee;
use dataflow::channels::pact::ParallelizationContract;
use dataflow::operators::capability::Capability;
use dataflow::operators::capability::mint as mint_capability;

struct OperatorShape<T: Timestamp> {
    name: String,
    notify: bool,
    index: usize,
    peers: usize,
    frontier: Vec<MutableAntichain<T>>,
    internal: Rc<RefCell<ChangeBatch<T>>>,
    outputs: usize,
}

/// Core data for the structure of an operator, minus scope and logic.
impl<T: Timestamp> OperatorShape<T> {
    fn new(name: String, notify: bool, index: usize, peers: usize) -> Self {
        OperatorShape {
            name: name,
            notify: notify,
            index: index,   // operator index, *not* worker/scope index.
            peers: peers,
            frontier: Vec::new(),
            internal: Rc::new(RefCell::new(ChangeBatch::new())),
            outputs: 0,
        }
    }
}

/// Builds operators with generic shape.
pub struct OperatorBuilder<G: Scope> {
    scope: G,
    shape: OperatorShape<G::Timestamp>,
}

impl<G: Scope> OperatorBuilder<G> {

    /// Allocates a new generic operator builder from its containing scope.
    pub fn new(name: String, notify: bool, mut scope: G) -> Self {

        panic!("`builder_ref.rs` is a work in progress; not yet appropriate for use");

        let index = scope.allocate_operator_index();
        let peers = scope.peers();

        OperatorBuilder {
            scope: scope,
            shape: OperatorShape::new(name, notify, index, peers),
        }
    }

    /// Adds a new input to a generic operator builder, returning the `Pull` implementor to use.
    pub fn new_input<D: Data, P>(&mut self, stream: &Stream<G, D>, pact: P) -> Box<Pull<(G::Timestamp, Content<D>)>>
    where
        P: ParallelizationContract<G::Timestamp, D> {

        let channel_id = self.scope.new_identifier();
        let (sender, receiver) = pact.connect(&mut self.scope, channel_id);

        let target = Target { index: self.shape.index, port: self.shape.frontier.len() };
        stream.connect_to(target, sender, channel_id);

        self.shape.frontier.push(MutableAntichain::new());

        receiver
    }

    /// Adds a new input to a generic operator builder, returning the `Push` implementor to use.
    pub fn new_output<D: Data>(&mut self) -> (Tee<G::Timestamp, D>, Stream<G, D>) {

        let (targets, registrar) = Tee::<G::Timestamp,D>::new();

        let source = Source { index: self.shape.index, port: self.shape.outputs };
        let stream = Stream::new(source, registrar, self.scope.clone());

        self.shape.outputs += 1;

        (targets, stream)
    }

    /// Creates an operator implementation from supplied logic constructor.
    pub fn build<B, L>(self, constructor: B)
    where
        B: FnOnce(Capability<G::Timestamp>) -> L,
        L: FnMut(
            &[MutableAntichain<G::Timestamp>],
            &mut [ChangeBatch<G::Timestamp>],
            &Rc<RefCell<ChangeBatch<G::Timestamp>>>,
            &mut [ChangeBatch<G::Timestamp>],
        )+'static
    {
        let mut scope = self.scope;
        let index = self.shape.index;

        let cap = mint_capability(Default::default(), self.shape.internal.clone());
        self.shape.internal.borrow_mut().clear();

        let logic = constructor(cap);

        let operator = OperatorCore {
            shape: self.shape,
            logic: logic,
        };

        scope.add_operator_with_index(operator, index);
    }
}

struct OperatorCore<T, L>
    where
        T: Timestamp,
        L: FnMut(
            &[MutableAntichain<T>],
            &mut [ChangeBatch<T>],
            &Rc<RefCell<ChangeBatch<T>>>,
            &mut [ChangeBatch<T>],
        )
{
    shape: OperatorShape<T>,
    logic: L,
}

impl<T, L> Operate<T> for OperatorCore<T, L>
    where
        T: Timestamp,
        L: FnMut(
            &[MutableAntichain<T>],
            &mut [ChangeBatch<T>],
            &Rc<RefCell<ChangeBatch<T>>>,
            &mut [ChangeBatch<T>],
        )
{
    fn inputs(&self) -> usize { self.shape.frontier.len() }
    fn outputs(&self) -> usize { self.shape.outputs }

    // announce internal topology as fully connected, and hold all default capabilities.
    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<ChangeBatch<T>>) {

        // by default, we reserve a capability for each output port at `Default::default()`.
        let mut internal = Vec::new();
        for _ in 0 .. self.shape.outputs {
            internal.push(ChangeBatch::new_from(Default::default(), self.shape.peers as i64));
        }

        let summary = vec![vec![Antichain::from_elem(Default::default()); self.shape.outputs]; self.shape.frontier.len()];

        (summary, internal)
    }

    // initialize self.frontier antichains as indicated by hosting scope.
    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>,
                                       count_map: &mut [ChangeBatch<T>]) {
        assert_eq!(count_map.len(), self.shape.frontier.len());
        for index in 0 .. count_map.len() {
            self.shape.frontier[index].update_iter(count_map[index].drain());
        }
    }

    // update self.frontier antichains as indicated by hosting scope.
    fn push_external_progress(&mut self, count_map: &mut [ChangeBatch<T>]) {
        for index in 0 .. count_map.len() {
            self.shape.frontier[index].update_iter(count_map[index].drain());
        }
    }

    // invoke user logic, propagate changes found in shared ChangeBatches.
    fn pull_internal_progress(&mut self, consumed: &mut [ChangeBatch<T>],
                                         internal: &mut [ChangeBatch<T>],
                                         produced: &mut [ChangeBatch<T>]) -> bool
    {
        // invoke supplied logic
        (self.logic)(&self.shape.frontier, consumed, &self.shape.internal, produced);

        // move batches of internal changes.
        let mut borrow = self.shape.internal.borrow_mut();
        for index in 1 .. internal.len() {
            internal[index].extend(borrow.iter().cloned());
        }
        internal[0].extend(borrow.drain());

        false   // no unannounced internal work
    }

    fn name(&self) -> String { self.shape.name.clone() }
    fn notify_me(&self) -> bool { self.shape.notify }
}

/// Owned state needed for buffering pusher.
pub struct OutputAllocation<T, D, P: Push<(T, Content<D>)>> {
    /// .
    pub time: Option<T>,
    /// .
    pub buffer: Vec<D>,
    /// .
    pub pusher: P,
}

// We also require a few helpful input handles:
mod handles {

    use std::rc::Rc;
    use std::cell::RefCell;

    use timely_communication::{Push, Pull};

    use order::PartialOrder;
    use progress::ChangeBatch;
    use progress::frontier::MutableAntichain;
    use dataflow::channels::Content;

    use super::OutputAllocation;

    struct InputHandle<'a, T: Ord+Clone+'a, D, P: Pull<(T, Content<D>)>+'a> {
        consumed: &'a mut ChangeBatch<T>,
        internal: &'a Rc<RefCell<ChangeBatch<T>>>,
        puller: &'a mut P,
        phantom: ::std::marker::PhantomData<D>,
    }

    impl<'a, T: Ord+Clone+'a, D, P: Pull<(T, Content<D>)>+'a> InputHandle<'a, T, D, P> {

        fn new(
            consumed: &'a mut ChangeBatch<T>,
            internal: &'a Rc<RefCell<ChangeBatch<T>>>,
            puller: &'a mut P) -> Self {

            InputHandle {
                consumed: consumed,
                internal: internal,
                puller: puller,
                phantom: ::std::marker::PhantomData,
            }
        }

        /// Retrieves the next timestamp and batch of data.
        #[inline]
        pub fn next(&mut self) -> Option<(&T, &mut Content<D>)> {
            if let Some((ref time, ref mut data)) = *self.puller.pull() {
                // TODO: This ignores empty allocations, which might be wrong.
                //       We may want to return them as part of zero-copy.
                if data.len() > 0 {
                    self.consumed.update(time.clone(), data.len() as i64);
                    Some((time, data))
                }
                else { None }
            }
            else { None }
        }
    }

    struct FrontieredInputHandle<'a, T: PartialOrder+Ord+Clone+'a, D, P: Pull<(T, Content<D>)>+'a> {
        input: InputHandle<'a, T, D, P>,
        pub frontier: &'a MutableAntichain<T>,
    }

    impl<'a, T: PartialOrder+Ord+Clone+'a, D, P: Pull<(T, Content<D>)>+'a> FrontieredInputHandle<'a, T, D, P> {

        fn new(input: InputHandle<'a, T, D, P>, frontier: &'a MutableAntichain<T>) -> Self {
            FrontieredInputHandle {
                input: input,
                frontier: frontier,
            }
        }

        /// Retrieves the next timestamp and batch of data.
        #[inline]
        pub fn next(&mut self) -> Option<(&T, &mut Content<D>)> {
            self.input.next()
        }
    }

    struct OutputHandle<'a, T: Ord+Clone+'a, D: 'a, P: Push<(T, Content<D>)>+'a> {
        internal: &'a Rc<RefCell<ChangeBatch<T>>>,  // to validate capabilities. (?)
        produced: &'a mut ChangeBatch<T>,
        pusher: &'a mut OutputAllocation<T, D, P>,
    }

    impl<'a, T: Ord+Clone+'a, D: 'a, P: Push<(T, Content<D>)>+'a> OutputHandle<'a, T, D, P> {
        // copy/paste buffer.rs?
    }

    impl<'a, T: Ord+Clone+'a, D: 'a, P: Push<(T, Content<D>)>+'a> Drop for OutputHandle<'a, T, D, P> {
        fn drop(&mut self) {
            // send a flush signal.
            self.pusher.pusher.push(&mut None);
        }
    }

}<commit_msg>hide builder_ref.rs for now<commit_after>//! Types to build operators with general shapes.

// TODO: Analogue to builder_rc.rs, which instead provides wrappers that only borrow ChangeBatch<T>
//       buffers, rather than wrapping them with Rc<RefCell<_>>. This removes dereferences from the
//       common path of having nothing to do, and could plausibly make it a bit faster to do nothing.<|endoftext|>


<commit_before>use itertools::Itertools;

pub fn main() {
    let mut i = 1;
    let mut next = "3113322113".to_owned();
    let mut part1 = 0;
    let mut part2 = 0;
    loop {
        next = next.chars()
                   .group_by(|&x| x)
                   .map(|(n, l)| {
                       let mut s = l.len().to_string();
                       s.push(n);
                       s
                   })
                   .collect::<String>();
        if i == 40 {
            part1 = next.len();
        }
        if i == 50 {
            part2 = next.len();
        }
        i += 1;
        if i == 51 {
            break;
        }
    }
    println!("Part 1: {}\nPart 2: {}", part1, part2);
}
<commit_msg>add test to day 10 rust<commit_after>use itertools::Itertools;

fn day10(input: &str) -> (usize, usize) {

    let mut i = 1;
    let mut next = String::from(input);
    let mut part1 = 0;
    let mut part2 = 0;
    loop {
        next = next.chars()
                   .group_by(|&x| x)
                   .map(|(n, l)| {
                       let mut s = l.len().to_string();
                       s.push(n);
                       s
                   })
                   .collect::<String>();
        if i == 40 {
            part1 = next.len();
        }
        if i == 50 {
            part2 = next.len();
        }
        i += 1;
        if i == 51 {
            break;
        }
    }
    return (part1, part2);
}

pub fn main() {
    let (part1, part2) = day10("3113322113");
    println!("Part 1: {}\nPart 2: {}", part1, part2);
}

#[test]
fn test() {
    let (part1, part2) = day10("3113322113");
    assert_eq!(part1, 329356);
    assert_eq!(part2, 4666278);
}
<|endoftext|>