<commit_before>//! Determine offset of stack pointer from function entry.
//!
//! Determine the value of the stack pointer at every location in the function
//! as an offset from the stack pointer's value at function entry.
//!
//! This analysis works off a very simple lattice, Top/Value/Bottom, where Value
//! is a single il::Constant.

use analysis::fixed_point;
use error::*;
use executor::eval;
use il;
use std::collections::HashMap;
use std::cmp::{Ordering, PartialOrd};
use types::Architecture;

/// Determine offset of stack pointer from program entry at each place in the
/// program.
pub fn stack_pointer_offsets<'f>(
    function: &'f il::Function,
    architecture: &Architecture
) -> Result<HashMap<il::RefProgramLocation<'f>, StackPointerOffset>> {

    let spoa = StackPointerOffsetAnalysis {
        stack_pointer: architecture.stack_pointer()
    };
    fixed_point::fixed_point_forward(spoa, function)
}

/// Returns true if there is a valid StackPointerOffset value for every location
/// in the function.
pub fn perfect<'f>(
    stack_pointer_offsets: &HashMap<il::RefProgramLocation<'f>, StackPointerOffset>
) -> bool {
    stack_pointer_offsets.iter().any(|(_, spo)| spo.is_value())
}

/// A constant value representing the value of the stack pointer at some point
/// in the function.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum StackPointerOffset {
    Top,
    Value(il::Constant),
    Bottom
}

impl StackPointerOffset {
    pub fn is_top(&self) -> bool {
        match *self {
            StackPointerOffset::Top => true,
            _ => false
        }
    }

    pub fn is_value(&self) -> bool {
        match *self {
            StackPointerOffset::Value(_) => true,
            _ => false
        }
    }

    pub fn value(&self) -> Option<&il::Constant> {
        if let StackPointerOffset::Value(ref constant) = *self {
            Some(constant)
        }
        else {
            None
        }
    }

    pub fn is_bottom(&self) -> bool {
        match *self {
            StackPointerOffset::Bottom => true,
            _ => false
        }
    }
}

impl PartialOrd for StackPointerOffset {
    fn partial_cmp(&self, other: &StackPointerOffset) -> Option<Ordering> {
        match *self {
            StackPointerOffset::Top => match *other {
                StackPointerOffset::Top => Some(Ordering::Equal),
                StackPointerOffset::Value(_) |
                StackPointerOffset::Bottom => Some(Ordering::Greater)
            },
            StackPointerOffset::Value(ref lhs) => match *other {
                StackPointerOffset::Top => Some(Ordering::Less),
                StackPointerOffset::Value(ref rhs) =>
                    if lhs == rhs { Some(Ordering::Equal) }
                    else { None},
                StackPointerOffset::Bottom => Some(Ordering::Greater)
            },
            StackPointerOffset::Bottom => match *other {
                StackPointerOffset::Top |
                StackPointerOffset::Value(_) => Some(Ordering::Less),
                StackPointerOffset::Bottom => Some(Ordering::Equal)
            }
        }
    }
}

struct StackPointerOffsetAnalysis {
    stack_pointer: il::Scalar
}

impl StackPointerOffsetAnalysis {
    /// Handle an operation for stack pointer offset analysis
    fn handle_operation(
        &self,
        operation: &il::Operation,
        stack_pointer_offset: StackPointerOffset
    ) -> Result<StackPointerOffset> {
        Ok(match *operation {
            // If we're assigning, operate off current stack pointer value
            il::Operation::Assign { ref dst, ref src } => {
                if *dst == self.stack_pointer {
                    match stack_pointer_offset {
                        StackPointerOffset::Top => StackPointerOffset::Top,
                        StackPointerOffset::Value(ref constant) => {
                            let expr = src.replace_scalar(&self.stack_pointer,
                                                          &constant.clone().into())?;
                            if expr.all_constants() {
                                StackPointerOffset::Value(eval(&expr)?.into())
                            }
                            else {
                                StackPointerOffset::Top
                            }
                        },
                        StackPointerOffset::Bottom => StackPointerOffset::Bottom
                    }
                }
                else {
                    stack_pointer_offset
                }
            },
            // If we are loading stack pointer, set it to top
            il::Operation::Load { ref dst, .. } => {
                if *dst == self.stack_pointer {
                    StackPointerOffset::Top
                }
                else {
                    stack_pointer_offset
                }
            },
            _ => stack_pointer_offset
        })
    }
}

/// Track the offset for the stack pointer at any point in the program
impl<'f> fixed_point::FixedPointAnalysis<'f, StackPointerOffset> for StackPointerOffsetAnalysis {
    fn trans(
        &self,
        location: il::RefProgramLocation<'f>,
        state: Option<StackPointerOffset>
    ) -> Result<StackPointerOffset> {

        // If we are the function entry, we set the value of the stack pointer
        // to 0.
        let stack_pointer_offset = match state {
            Some(state) => state,
            None => {
                // Get function entry
                let function_entry =
                    il::RefProgramLocation::from_function(location.function())
                        .ok_or("Unable to get function entry")?;

                if location == function_entry {
                    StackPointerOffset::Value(il::const_(0, 32))
                }
                else {
                    StackPointerOffset::Top
                }
            }
        };

        Ok(match *location.function_location() {
            il::RefFunctionLocation::Instruction(_, ref instruction) =>
                self.handle_operation(instruction.operation(),
                                      stack_pointer_offset)?,
            _ => stack_pointer_offset
        })
    }

    fn join(&self, state0: StackPointerOffset, state1: &StackPointerOffset)
        -> Result<StackPointerOffset> {

        Ok(match state0 {
            StackPointerOffset::Top => StackPointerOffset::Top,
            StackPointerOffset::Value(v0) => {
                match *state1 {
                    StackPointerOffset::Top => StackPointerOffset::Top,
                    StackPointerOffset::Value(ref v1) => {
                        if v0 == *v1 {
                            StackPointerOffset::Value(v0)
                        }
                        else {
                            StackPointerOffset::Top
                        }
                    },
                    StackPointerOffset::Bottom => StackPointerOffset::Value(v0)
                }
            },
            StackPointerOffset::Bottom => {
                match *state1 {
                    StackPointerOffset::Top => StackPointerOffset::Top,
                    StackPointerOffset::Value(ref v1) =>
                        StackPointerOffset::Value(v1.clone()),
                    StackPointerOffset::Bottom => StackPointerOffset::Bottom
                }
            }
        })
    }
}<commit_msg>fix stack_pointer_offsets::perfect<commit_after>//! Determine offset of stack pointer from function entry.
//!
//! Determine the value of the stack pointer at every location in the function
//! as an offset from the stack pointer's value at function entry.
//!
//! This analysis works off a very simple lattice, Top/Value/Bottom, where Value
//! is a single il::Constant.

use analysis::fixed_point;
use error::*;
use executor::eval;
use il;
use std::collections::HashMap;
use std::cmp::{Ordering, PartialOrd};
use types::Architecture;

/// Determine offset of stack pointer from program entry at each place in the
/// program.
pub fn stack_pointer_offsets<'f>(
    function: &'f il::Function,
    architecture: &Architecture
) -> Result<HashMap<il::RefProgramLocation<'f>, StackPointerOffset>> {

    let spoa = StackPointerOffsetAnalysis {
        stack_pointer: architecture.stack_pointer()
    };
    fixed_point::fixed_point_forward(spoa, function)
}

/// Returns true if there is a valid StackPointerOffset value for every location
/// in the function.
pub fn perfect<'f>(
    stack_pointer_offsets: &HashMap<il::RefProgramLocation<'f>, StackPointerOffset>
) -> bool {
    stack_pointer_offsets.iter().all(|(_, spo)| spo.is_value())
}

/// A constant value representing the value of the stack pointer at some point
/// in the function.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum StackPointerOffset {
    Top,
    Value(il::Constant),
    Bottom
}

impl StackPointerOffset {
    pub fn is_top(&self) -> bool {
        match *self {
            StackPointerOffset::Top => true,
            _ => false
        }
    }

    pub fn is_value(&self) -> bool {
        match *self {
            StackPointerOffset::Value(_) => true,
            _ => false
        }
    }

    pub fn value(&self) -> Option<&il::Constant> {
        if let StackPointerOffset::Value(ref constant) = *self {
            Some(constant)
        }
        else {
            None
        }
    }

    pub fn is_bottom(&self) -> bool {
        match *self {
            StackPointerOffset::Bottom => true,
            _ => false
        }
    }
}

impl PartialOrd for StackPointerOffset {
    fn partial_cmp(&self, other: &StackPointerOffset) -> Option<Ordering> {
        match *self {
            StackPointerOffset::Top => match *other {
                StackPointerOffset::Top => Some(Ordering::Equal),
                StackPointerOffset::Value(_) |
                StackPointerOffset::Bottom => Some(Ordering::Greater)
            },
            StackPointerOffset::Value(ref lhs) => match *other {
                StackPointerOffset::Top => Some(Ordering::Less),
                StackPointerOffset::Value(ref rhs) =>
                    if lhs == rhs { Some(Ordering::Equal) }
                    else { None},
                StackPointerOffset::Bottom => Some(Ordering::Greater)
            },
            StackPointerOffset::Bottom => match *other {
                StackPointerOffset::Top |
                StackPointerOffset::Value(_) => Some(Ordering::Less),
                StackPointerOffset::Bottom => Some(Ordering::Equal)
            }
        }
    }
}

struct StackPointerOffsetAnalysis {
    stack_pointer: il::Scalar
}

impl StackPointerOffsetAnalysis {
    /// Handle an operation for stack pointer offset analysis
    fn handle_operation(
        &self,
        operation: &il::Operation,
        stack_pointer_offset: StackPointerOffset
    ) -> Result<StackPointerOffset> {
        Ok(match *operation {
            // If we're assigning, operate off current stack pointer value
            il::Operation::Assign { ref dst, ref src } => {
                if *dst == self.stack_pointer {
                    match stack_pointer_offset {
                        StackPointerOffset::Top => StackPointerOffset::Top,
                        StackPointerOffset::Value(ref constant) => {
                            let expr = src.replace_scalar(&self.stack_pointer,
                                                          &constant.clone().into())?;
                            if expr.all_constants() {
                                StackPointerOffset::Value(eval(&expr)?.into())
                            }
                            else {
                                StackPointerOffset::Top
                            }
                        },
                        StackPointerOffset::Bottom => StackPointerOffset::Bottom
                    }
                }
                else {
                    stack_pointer_offset
                }
            },
            // If we are loading stack pointer, set it to top
            il::Operation::Load { ref dst, .. } => {
                if *dst == self.stack_pointer {
                    StackPointerOffset::Top
                }
                else {
                    stack_pointer_offset
                }
            },
            _ => stack_pointer_offset
        })
    }
}

/// Track the offset for the stack pointer at any point in the program
impl<'f> fixed_point::FixedPointAnalysis<'f, StackPointerOffset> for StackPointerOffsetAnalysis {
    fn trans(
        &self,
        location: il::RefProgramLocation<'f>,
        state: Option<StackPointerOffset>
    ) -> Result<StackPointerOffset> {

        // If we are the function entry, we set the value of the stack pointer
        // to 0.
        let stack_pointer_offset = match state {
            Some(state) => state,
            None => {
                // Get function entry
                let function_entry =
                    il::RefProgramLocation::from_function(location.function())
                        .ok_or("Unable to get function entry")?;

                if location == function_entry {
                    StackPointerOffset::Value(il::const_(0, 32))
                }
                else {
                    StackPointerOffset::Top
                }
            }
        };

        Ok(match *location.function_location() {
            il::RefFunctionLocation::Instruction(_, ref instruction) =>
                self.handle_operation(instruction.operation(),
                                      stack_pointer_offset)?,
            _ => stack_pointer_offset
        })
    }

    fn join(&self, state0: StackPointerOffset, state1: &StackPointerOffset)
        -> Result<StackPointerOffset> {

        Ok(match state0 {
            StackPointerOffset::Top => StackPointerOffset::Top,
            StackPointerOffset::Value(v0) => {
                match *state1 {
                    StackPointerOffset::Top => StackPointerOffset::Top,
                    StackPointerOffset::Value(ref v1) => {
                        if v0 == *v1 {
                            StackPointerOffset::Value(v0)
                        }
                        else {
                            StackPointerOffset::Top
                        }
                    },
                    StackPointerOffset::Bottom => StackPointerOffset::Value(v0)
                }
            },
            StackPointerOffset::Bottom => {
                match *state1 {
                    StackPointerOffset::Top => StackPointerOffset::Top,
                    StackPointerOffset::Value(ref v1) =>
                        StackPointerOffset::Value(v1.clone()),
                    StackPointerOffset::Bottom => StackPointerOffset::Bottom
                }
            }
        })
    }
}<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

error_chain! {
    types {
        ContactError, ContactErrorKind, ResultExt, Result;
    }

    links {
        StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
        RefError(::libimagentryref::error::RefError, ::libimagentryref::error::RefErrorKind);
    }

    foreign_links {
        Io(::std::io::Error);
        TomlQueryError(::toml_query::error::Error);
        VObjectError(::vobject::ParseError);
    }

    errors {

        HeaderTypeError(ty: &'static str, loc: &'static str) {
            description("Type error in header")
            display("Type error in header, expected {} at '{}', found other type", ty, loc)
        }

    }
}

<commit_msg>Rely on own clone of rust-vobject<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

error_chain! {
    types {
        ContactError, ContactErrorKind, ResultExt, Result;
    }

    links {
        StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
        RefError(::libimagentryref::error::RefError, ::libimagentryref::error::RefErrorKind);
        VObjectError(::vobject::error::VObjectError, ::vobject::error::VObjectErrorKind);
    }

    foreign_links {
        Io(::std::io::Error);
        TomlQueryError(::toml_query::error::Error);
    }

    errors {

        HeaderTypeError(ty: &'static str, loc: &'static str) {
            description("Type error in header")
            display("Type error in header, expected {} at '{}', found other type", ty, loc)
        }

    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_elm;

use std::env;
use std::fs::File;
use std::io::{Read, Error};
use std::path::Path;

#[allow(dead_code)]
#[derive(Elm)]
struct Simple {
    name: String
}

#[test]
fn should_assert_elm_generation_was_done() {
	let root = env::current_dir().unwrap();
    let mut path = root.clone();
    path.push("generated");
    path.push("Simple.elm");

    assert!(path.exists());
    assert!(path.is_file());

    let actual = contents_of(&path).unwrap();

    let mut expected_path = root.clone();
    expected_path.push("tests");
    expected_path.push("assets");
    expected_path.push("Simple.test.elm");

    let expected = contents_of(&expected_path).unwrap();

    assert_eq!(actual, expected);
}

fn contents_of(path: &Path) -> Result<String, Error> {
    let mut file = File::open(path)?;
    let mut content = String::new();
    file.read_to_string(&mut content)?;

    Ok(content)
}
<commit_msg>Make content check accept a model name<commit_after>#[macro_use]
extern crate serde_elm;

use std::env;
use std::fs::File;
use std::io::{Read, Error};
use std::path::Path;

#[allow(dead_code)]
#[derive(Elm)]
struct Simple {
    name: String
}

#[test]
fn should_assert_elm_generation_was_done() {
	let model_name = "Simple";
	assert!(content_equal_for(model_name))
}

fn content_equal_for<S>(model_name: S) -> bool where S: Into<String> {
	let model_name = model_name.into();
	let root = env::current_dir().unwrap();
    let mut path = root.clone();
    path.push("generated");
    path.push(format!("{}.elm", model_name));

    assert!(path.exists());
    assert!(path.is_file());

    let actual = contents_of(&path).unwrap();

    let mut expected_path = root.clone();
    expected_path.push("tests");
    expected_path.push("assets");
    expected_path.push(format!("{}.test.elm", model_name));

    let expected = contents_of(&expected_path).unwrap();

    actual == expected
}

fn contents_of(path: &Path) -> Result<String, Error> {
    let mut file = File::open(path)?;
    let mut content = String::new();
    file.read_to_string(&mut content)?;

    Ok(content)
}
<|endoftext|>


<commit_before>use super::*;

#[derive(Debug, Clone, Hash, PartialEq)]
pub enum ArenaInput {
    Start,
    Turn(Direction),
}

impl ArenaInput {
    pub fn process_into_updates(self, arena: &Arena, player_id: PlayerId) -> Vec<ArenaUpdate> {
        match self {
            ArenaInput::Start => {
                if arena.started.is_some() {
                    trace!(
                        "Refusing to start arena that is already started: {}",
                        arena.id
                    );
                    return vec![];
                }

                let mut updates = Vec::with_capacity(
                    arena.lightcycles.len() + arena.trails.len() + (arena.players.len() * 2) + 1,
                );

                // remove existing lightcycles
                arena
                    .lightcycles
                    .keys()
                    .copied()
                    .for_each(|id| updates.push(ArenaUpdate::RemoveLightcycle(id)));

                // remove existing trails
                arena
                    .trails
                    .keys()
                    .copied()
                    .for_each(|id| updates.push(ArenaUpdate::RemoveTrail(id)));

                // add new lightcycles and trails
                let player_ids = arena.players.keys().copied().collect();
                calculate_spawnpoints(player_ids).drain(..).for_each(
                    |(player_id, spawn_position, spawn_direction)| {
                        updates.push(ArenaUpdate::AddLightcycle(
                            player_id,
                            Lightcycle {
                                position: spawn_position,
                                direction: spawn_direction,
                                ..Default::default()
                            },
                        ));
                        updates.push(ArenaUpdate::AddTrail(
                            player_id,
                            Trail {
                                points: vec![spawn_position, spawn_position],
                            },
                        ));
                    },
                );

                // begin countdown
                updates.push(ArenaUpdate::Start(
                    Utc::now() + OldDuration::seconds(ARENA_START_TIMER_SECONDS),
                ));

                updates
            }

            ArenaInput::Turn(direction) => {
                let lightcycle = match arena.lightcycles.get(&player_id) {
                    Some(lightcycle) => lightcycle,
                    None => {
                        error!("Lightcycle {} not found", player_id);
                        return vec![];
                    }
                };

                if lightcycle.dead {
                    trace!("Refusing to turn dead lightcycle");
                    return vec![];
                }

                if lightcycle.direction.is_opposite(direction) {
                    trace!("Refusing to turn lightcycle in opposite direction");
                    return vec![];
                }

                return vec![
                    ArenaUpdate::UpdateTrailAppendPoint(player_id, lightcycle.position),
                    ArenaUpdate::UpdateLightcycleDirection(player_id, direction),
                ];
            }
        }
    }
}
<commit_msg>fixed turnable lightcycles in stopped arenas<commit_after>use super::*;

#[derive(Debug, Clone, Hash, PartialEq)]
pub enum ArenaInput {
    Start,
    Turn(Direction),
}

impl ArenaInput {
    pub fn process_into_updates(self, arena: &Arena, player_id: PlayerId) -> Vec<ArenaUpdate> {
        match self {
            ArenaInput::Start => {
                if arena.started.is_some() {
                    trace!(
                        "Refusing to start arena that is already started: {}",
                        arena.id
                    );
                    return vec![];
                }

                let mut updates = Vec::with_capacity(
                    arena.lightcycles.len() + arena.trails.len() + (arena.players.len() * 2) + 1,
                );

                // remove existing lightcycles
                arena
                    .lightcycles
                    .keys()
                    .copied()
                    .for_each(|id| updates.push(ArenaUpdate::RemoveLightcycle(id)));

                // remove existing trails
                arena
                    .trails
                    .keys()
                    .copied()
                    .for_each(|id| updates.push(ArenaUpdate::RemoveTrail(id)));

                // add new lightcycles and trails
                let player_ids = arena.players.keys().copied().collect();
                calculate_spawnpoints(player_ids).drain(..).for_each(
                    |(player_id, spawn_position, spawn_direction)| {
                        updates.push(ArenaUpdate::AddLightcycle(
                            player_id,
                            Lightcycle {
                                position: spawn_position,
                                direction: spawn_direction,
                                ..Default::default()
                            },
                        ));
                        updates.push(ArenaUpdate::AddTrail(
                            player_id,
                            Trail {
                                points: vec![spawn_position, spawn_position],
                            },
                        ));
                    },
                );

                // begin countdown
                updates.push(ArenaUpdate::Start(
                    Utc::now() + OldDuration::seconds(ARENA_START_TIMER_SECONDS),
                ));

                updates
            }

            ArenaInput::Turn(direction) => {
                let lightcycle = match arena.lightcycles.get(&player_id) {
                    Some(lightcycle) => lightcycle,
                    None => {
                        error!("Lightcycle {} not found", player_id);
                        return vec![];
                    }
                };

                match arena.started {
                    None => {
                        trace!("Refusing to turn lightcycle in stopped arena");
                        return vec![];
                    }
                    Some(started) => {
                        let now = Utc::now();
                        if now < started {
                            trace!("Refusing to turn lightcycle before arena has started");
                            return vec![];
                        }
                    }
                }

                if lightcycle.dead {
                    trace!("Refusing to turn dead lightcycle");
                    return vec![];
                }

                if lightcycle.direction.is_opposite(direction) {
                    trace!("Refusing to turn lightcycle in opposite direction");
                    return vec![];
                }

                return vec![
                    ArenaUpdate::UpdateTrailAppendPoint(player_id, lightcycle.position),
                    ArenaUpdate::UpdateLightcycleDirection(player_id, direction),
                ];
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::env;
use std::process::{Stdio, exit};

use tokio::{
    runtime::Handle,
    io::AsyncWriteExt,
    task::JoinHandle,
    process::{Command, ChildStdin},
};

/// The environment variable that is set to indicate that the current process is a server process
pub const RENDERER_PROCESS_ENV_VAR: &str = "RUN_TURTLE_CANVAS";

#[derive(Debug)]
pub struct RendererServerProcess {
    task_handle: Option<JoinHandle<()>>,
    /// A handle to the stdin of the child process
    child_stdin: ChildStdin,
}

impl RendererServerProcess {
    /// Spawn a new process for the renderer
    pub async fn spawn() -> Self {
        let current_exe = env::current_exe()
            .expect("Could not read path of the currently running executable");

        // The new process is the same executable as this process but with a special environment
        // variable passed in
        let mut child = Command::new(current_exe)
            .env(RENDERER_PROCESS_ENV_VAR, "true")
            // Pipe input so we can communicate with the spawned process
            //
            // stdout/stderr will be inherited from the current process
            .stdin(Stdio::piped())
            .spawn()
            .expect("failed to start separate process for renderer");

        let child_stdin = child.stdin.take()
            .expect("renderer process was not spawned with a handle to stdin");

        // Ensure the child process is spawned in the runtime so it can
        // make progress on its own while we send it input.
        let task_handle = Some(tokio::spawn(async {
            // We want to await in a separate task because otherwise the current task would not
            // make any progress until the child process is complete
            let status = child.await
                .expect("child process encountered an error");

            if status.success() {
                // The window/renderer process was closed normally
                exit(0);
            } else {
                // Something went wrong, likely the other thread panicked
                exit(1);
            }
        }));

        Self {task_handle, child_stdin}
    }

    /// Writes the given bytes followed by a newline b'\n' to the stdin of the process
    ///
    /// Unlike `std::io::Write::write`, this returns an error in the case all of the bytes could
    /// not be written for some reason.
    pub async fn writeln<S: AsRef<[u8]>>(&mut self, data: S) -> io::Result<()> {
        let data = data.as_ref();
        self.child_stdin.write_all(data).await?;
        self.child_stdin.write_all(&[b'\n']).await?;

        Ok(())
    }
}

impl Drop for RendererServerProcess {
    fn drop(&mut self) {
        use std::thread;

        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        let runtime = Handle::current();
        // This unwrap is safe because no struct gets dropped twice
        let task_handle = self.task_handle.take().unwrap();
        runtime.block_on(task_handle).unwrap_or_else(|_| {
            // If this returns an error, the other thread panicked
            exit(1);
        });
    }
}
<commit_msg>Need to spawn a new runtime in Drop because the original runtime may have already been destroyed<commit_after>use std::io;
use std::env;
use std::process::{Stdio, exit};

use tokio::{
    runtime,
    io::AsyncWriteExt,
    task::JoinHandle,
    process::{Command, ChildStdin},
};

/// The environment variable that is set to indicate that the current process is a server process
pub const RENDERER_PROCESS_ENV_VAR: &str = "RUN_TURTLE_CANVAS";

#[derive(Debug)]
pub struct RendererServerProcess {
    task_handle: Option<JoinHandle<()>>,
    /// A handle to the stdin of the child process
    child_stdin: ChildStdin,
}

impl RendererServerProcess {
    /// Spawn a new process for the renderer
    pub async fn spawn() -> Self {
        let current_exe = env::current_exe()
            .expect("Could not read path of the currently running executable");

        // The new process is the same executable as this process but with a special environment
        // variable passed in
        let mut child = Command::new(current_exe)
            .env(RENDERER_PROCESS_ENV_VAR, "true")
            // Pipe input so we can communicate with the spawned process
            //
            // stdout/stderr will be inherited from the current process
            .stdin(Stdio::piped())
            .spawn()
            .expect("failed to start separate process for renderer");

        let child_stdin = child.stdin.take()
            .expect("renderer process was not spawned with a handle to stdin");

        // Ensure the child process is spawned in the runtime so it can
        // make progress on its own while we send it input.
        let task_handle = Some(tokio::spawn(async {
            // We want to await in a separate task because otherwise the current task would not
            // make any progress until the child process is complete
            let status = child.await
                .expect("child process encountered an error");

            if status.success() {
                // The window/renderer process was closed normally
                exit(0);
            } else {
                // Something went wrong, likely the other thread panicked
                exit(1);
            }
        }));

        Self {task_handle, child_stdin}
    }

    /// Writes the given bytes followed by a newline b'\n' to the stdin of the process
    ///
    /// Unlike `std::io::Write::write`, this returns an error in the case all of the bytes could
    /// not be written for some reason.
    pub async fn writeln<S: AsRef<[u8]>>(&mut self, data: S) -> io::Result<()> {
        let data = data.as_ref();
        self.child_stdin.write_all(data).await?;
        self.child_stdin.write_all(&[b'\n']).await?;

        Ok(())
    }
}

impl Drop for RendererServerProcess {
    fn drop(&mut self) {
        use std::thread;

        // If the current thread is panicking, we want to abort right away
        // because otherwise there is code in the rendering thread that will call
        // process::exit(0) and then the exit code will be 0 instead of 1
        if thread::panicking() {
            exit(1);
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open
        // Need to spawn a new runtime because the current one would have already been dropped
        let mut runtime = runtime::Builder::new()
            .basic_scheduler()
            .build()
            .expect("unable to spawn tokio runtime to wait on turtle server process");

        // This unwrap is safe because no struct gets dropped twice
        let task_handle = self.task_handle.take().unwrap();
        runtime.block_on(task_handle).unwrap_or_else(|_| {
            // If this returns an error, the other thread panicked
            exit(1);
        });
    }
}
<|endoftext|>


<commit_before><commit_msg>[vm] Make TYPE_RESOLUTION_FAILURE an invariant violation<commit_after><|endoftext|>


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

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::ErrorKind;
use std::io::{Seek, Write, SeekFrom};
use std::fs::{OpenOptions, read_dir};
use std::os::unix::prelude::AsRawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use devicemapper::Device;
use devicemapper::types::{Bytes, Sectors};
use devicemapper::consts::SECTOR_SIZE;
use time::Timespec;
use uuid::Uuid;

use consts::IEC;
use engine::{DevUuid, EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{StaticHeader, BDA, validate_mda_size};
use super::engine::DevOwnership;
pub use super::BlockDevSave;

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi as u64);

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        let dev = try!(Device::from_str(&path.to_string_lossy()));
        devices.insert(dev);
    }
    Ok(devices)
}

/// Find all Stratis Blockdevs.
///
/// Returns a map of pool uuids to maps of blockdev uuids to blockdevs.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<DevUuid, BlockDev>>> {

    /// If a Path refers to a valid Stratis blockdev, return a BlockDev
    /// struct. Otherwise, return None. Return an error if there was
    /// a problem inspecting the device.
    fn setup(devnode: &Path) -> EngineResult<Option<BlockDev>> {
        let dev = try!(Device::from_str(&devnode.to_string_lossy()));

        let mut f = try!(OpenOptions::new()
            .read(true)
            .open(devnode));

        if let Some(bda) = BDA::load(&mut f).ok() {
            Ok(Some(BlockDev {
                dev: dev,
                devnode: devnode.to_owned(),
                bda: bda,
            }))
        } else {
            Ok(None)
        }
    }

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let devnode = match dir_e {
            Ok(d) => d.path(),
            Err(_) => continue,
        };

        match setup(&devnode) {
            Ok(Some(blockdev)) => {
                pool_map.entry(blockdev.pool_uuid().clone())
                    .or_insert_with(HashMap::new)
                    .insert(blockdev.uuid().clone(), blockdev);
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Zero sectors at the given offset
pub fn wipe_sectors(path: &Path, offset: Sectors, sector_count: Sectors) -> EngineResult<()> {
    let mut f = try!(OpenOptions::new()
        .write(true)
        .open(path));

    let zeroed = [0u8; SECTOR_SIZE];

    // set the start point to the offset
    try!(f.seek(SeekFrom::Start(*offset)));
    for _ in 0..*sector_count {
        try!(f.write_all(&zeroed));
    }
    try!(f.flush());
    Ok(())
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {
    /// Gets device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the blockdev's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.path().ok_or_else(|| {
            io::Error::new(ErrorKind::InvalidInput,
                           format!("could not get device node from dev {}", dev.dstr()))
        }));
        let mut f = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)
            .map_err(|_| {
                io::Error::new(ErrorKind::PermissionDenied,
                               format!("Could not open {}", devnode.display()))
            }));

        let dev_size = try!(blkdev_size(&f));

        let ownership = match StaticHeader::determine_ownership(&mut f) {
            Ok(ownership) => ownership,
            Err(err) => {
                let error_message = format!("{} for device {}", err, devnode.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            }
        };

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let error_str = format!("First 8K of {} not zeroed", devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    // TODO: Fix this code.  We should deal with any number of blockdevs
    //
    if add_devs.len() < 2 {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "Need at least 2 blockdevs to create a pool".into()));
    }

    let mut bds = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = try!(BDA::initialize(&mut f,
                                       pool_uuid,
                                       &Uuid::new_v4(),
                                       mda_size,
                                       dev_size.sectors()));

        let bd = BlockDev {
            dev: dev,
            devnode: devnode.clone(),
            bda: bda,
        };
        bds.push(bd);
    }
    Ok(bds)
}

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
}

impl BlockDev {
    pub fn to_save(&self) -> BlockDevSave {
        BlockDevSave {
            devnode: self.devnode.clone(),
            total_size: self.size(),
        }
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    /// Get the "x:y" device string for this blockdev
    pub fn dstr(&self) -> String {
        self.dev.dstr()
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    pub fn load_state(&self) -> EngineResult<Option<Vec<u8>>> {
        let mut f = try!(OpenOptions::new().read(true).open(&self.devnode));
        self.bda.load_state(&mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// The /dev/mapper/<name> device is not immediately available for use.
    /// TODO: Implement wait for event or poll.
    pub fn wait_for_dm() {
        thread::sleep(Duration::from_millis(500))
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }
}
<commit_msg>Do not return an error unnecessarily<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::ErrorKind;
use std::io::{Seek, Write, SeekFrom};
use std::fs::{OpenOptions, read_dir};
use std::os::unix::prelude::AsRawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use devicemapper::Device;
use devicemapper::types::{Bytes, Sectors};
use devicemapper::consts::SECTOR_SIZE;
use time::Timespec;
use uuid::Uuid;

use consts::IEC;
use engine::{DevUuid, EngineResult, EngineError, ErrorEnum, PoolUuid};
use super::metadata::{StaticHeader, BDA, validate_mda_size};
use super::engine::DevOwnership;
pub use super::BlockDevSave;

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi as u64);

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        let dev = try!(Device::from_str(&path.to_string_lossy()));
        devices.insert(dev);
    }
    Ok(devices)
}

/// Find all Stratis Blockdevs.
///
/// Returns a map of pool uuids to maps of blockdev uuids to blockdevs.
pub fn find_all() -> EngineResult<HashMap<PoolUuid, HashMap<DevUuid, BlockDev>>> {

    /// If a Path refers to a valid Stratis blockdev, return a BlockDev
    /// struct. Otherwise, return None. Return an error if there was
    /// a problem inspecting the device.
    fn setup(devnode: &Path) -> EngineResult<Option<BlockDev>> {
        let mut f = try!(OpenOptions::new()
            .read(true)
            .open(devnode));

        if let Some(bda) = BDA::load(&mut f).ok() {
            let dev = try!(Device::from_str(&devnode.to_string_lossy()));
            Ok(Some(BlockDev {
                dev: dev,
                devnode: devnode.to_owned(),
                bda: bda,
            }))
        } else {
            Ok(None)
        }
    }

    let mut pool_map = HashMap::new();
    for dir_e in try!(read_dir("/dev")) {
        let devnode = match dir_e {
            Ok(d) => d.path(),
            Err(_) => continue,
        };

        match setup(&devnode) {
            Ok(Some(blockdev)) => {
                pool_map.entry(blockdev.pool_uuid().clone())
                    .or_insert_with(HashMap::new)
                    .insert(blockdev.uuid().clone(), blockdev);
            }
            _ => continue,
        };
    }

    Ok(pool_map)
}

/// Zero sectors at the given offset
pub fn wipe_sectors(path: &Path, offset: Sectors, sector_count: Sectors) -> EngineResult<()> {
    let mut f = try!(OpenOptions::new()
        .write(true)
        .open(path));

    let zeroed = [0u8; SECTOR_SIZE];

    // set the start point to the offset
    try!(f.seek(SeekFrom::Start(*offset)));
    for _ in 0..*sector_count {
        try!(f.write_all(&zeroed));
    }
    try!(f.flush());
    Ok(())
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {
    /// Gets device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the blockdev's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.path().ok_or_else(|| {
            io::Error::new(ErrorKind::InvalidInput,
                           format!("could not get device node from dev {}", dev.dstr()))
        }));
        let mut f = try!(OpenOptions::new()
            .read(true)
            .write(true)
            .open(&devnode)
            .map_err(|_| {
                io::Error::new(ErrorKind::PermissionDenied,
                               format!("Could not open {}", devnode.display()))
            }));

        let dev_size = try!(blkdev_size(&f));

        let ownership = match StaticHeader::determine_ownership(&mut f) {
            Ok(ownership) => ownership,
            Err(err) => {
                let error_message = format!("{} for device {}", err, devnode.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            }
        };

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let error_str = format!("First 8K of {} not zeroed", devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    // TODO: Fix this code.  We should deal with any number of blockdevs
    //
    if add_devs.len() < 2 {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "Need at least 2 blockdevs to create a pool".into()));
    }

    let mut bds = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = try!(BDA::initialize(&mut f,
                                       pool_uuid,
                                       &Uuid::new_v4(),
                                       mda_size,
                                       dev_size.sectors()));

        let bd = BlockDev {
            dev: dev,
            devnode: devnode.clone(),
            bda: bda,
        };
        bds.push(bd);
    }
    Ok(bds)
}

#[derive(Debug)]
pub struct BlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
}

impl BlockDev {
    pub fn to_save(&self) -> BlockDevSave {
        BlockDevSave {
            devnode: self.devnode.clone(),
            total_size: self.size(),
        }
    }

    pub fn wipe_metadata(self) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        BDA::wipe(&mut f)
    }

    /// Get the "x:y" device string for this blockdev
    pub fn dstr(&self) -> String {
        self.dev.dstr()
    }

    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        let mut f = try!(OpenOptions::new().write(true).open(&self.devnode));
        self.bda.save_state(time, metadata, &mut f)
    }

    pub fn load_state(&self) -> EngineResult<Option<Vec<u8>>> {
        let mut f = try!(OpenOptions::new().read(true).open(&self.devnode));
        self.bda.load_state(&mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.bda.size();
        let size = self.size();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// The /dev/mapper/<name> device is not immediately available for use.
    /// TODO: Implement wait for event or poll.
    pub fn wait_for_dm() {
        thread::sleep(Duration::from_millis(500))
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// The device's size.
    pub fn size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&Timespec> {
        self.bda.last_update_time()
    }
}
<|endoftext|>


<commit_before>#[doc(hidden)]
pub mod filter;
mod joins;

use expression::{Expression, SelectableExpression, NonAggregate};
use query_builder::*;
#[doc(hidden)]
pub use self::joins::{InnerJoinSource, LeftOuterJoinSource};
use types::{FromSqlRow, NativeSqlType};

pub use self::joins::JoinTo;

pub trait Queriable<ST: NativeSqlType> {
    type Row: FromSqlRow<ST>;

    fn build(row: Self::Row) -> Self;
}

pub trait QuerySource: Sized {
    fn from_clause(&self, out: &mut QueryBuilder) -> BuildQueryResult;
}

pub trait Column: Expression {
    type Table: Table;

    fn name() -> &'static str;
}

pub trait Table: QuerySource + AsQuery + Sized {
    type PrimaryKey: Column<Table=Self> + Expression + NonAggregate;
    type AllColumns: SelectableExpression<Self>;

    fn name() -> &'static str;
    fn primary_key(&self) -> Self::PrimaryKey;
    fn all_columns() -> Self::AllColumns;

    fn inner_join<T>(self, other: T) -> InnerJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        InnerJoinSource::new(self, other)
    }

    fn left_outer_join<T>(self, other: T) -> LeftOuterJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        LeftOuterJoinSource::new(self, other)
    }
}

impl<T: Table> UpdateTarget for T {
    type Table = Self;

    fn where_clause(&self, _out: &mut QueryBuilder) -> BuildQueryResult {
        Ok(())
    }

    fn table(&self) -> &Self::Table {
        self
    }
}
<commit_msg>Document the Queriable module<commit_after>#[doc(hidden)]
pub mod filter;
mod joins;

use expression::{Expression, SelectableExpression, NonAggregate};
use query_builder::*;
#[doc(hidden)]
pub use self::joins::{InnerJoinSource, LeftOuterJoinSource};
use types::{FromSqlRow, NativeSqlType};

pub use self::joins::JoinTo;

/// Trait indicating that a record can be queried from the database. This trait
/// can be derived automatically. See the [codegen
/// documentation](https://github.com/sgrif/yaqb/tree/master/yaqb_codegen#derivequeriable)
/// for more.
pub trait Queriable<ST: NativeSqlType> {
    type Row: FromSqlRow<ST>;

    fn build(row: Self::Row) -> Self;
}

#[doc(hidden)]
pub trait QuerySource: Sized {
    fn from_clause(&self, out: &mut QueryBuilder) -> BuildQueryResult;
}

/// A column on a database table. Types which implement this trait should have
/// been generated by the [`table!`
/// macro](http://sgrif.github.io/yaqb/yaqb/macro.table!.html).
pub trait Column: Expression {
    type Table: Table;

    fn name() -> &'static str;
}

/// A SQL database table. Types which implement this trait should have
/// been generated by the [`table!`
/// macro](http://sgrif.github.io/yaqb/yaqb/macro.table!.html).
pub trait Table: QuerySource + AsQuery + Sized {
    type PrimaryKey: Column<Table=Self> + Expression + NonAggregate;
    type AllColumns: SelectableExpression<Self>;

    fn name() -> &'static str;
    fn primary_key(&self) -> Self::PrimaryKey;
    fn all_columns() -> Self::AllColumns;

    fn inner_join<T>(self, other: T) -> InnerJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        InnerJoinSource::new(self, other)
    }

    fn left_outer_join<T>(self, other: T) -> LeftOuterJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        LeftOuterJoinSource::new(self, other)
    }
}

impl<T: Table> UpdateTarget for T {
    type Table = Self;

    fn where_clause(&self, _out: &mut QueryBuilder) -> BuildQueryResult {
        Ok(())
    }

    fn table(&self) -> &Self::Table {
        self
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::{mem, time};
use torrent::{Info, Peer, Bitfield};
use control::cio;

mod rarest;
mod sequential;

#[cfg(test)]
mod tests;

#[derive(Clone, Debug)]
pub struct Picker {
    /// Number of blocks per piece
    scale: u32,
    /// Number of detected seeders
    seeders: u16,
    /// Set of pieces which have blocks waiting. These should be prioritized.
    downloading: HashMap<u32, Vec<Downloading>>,
    /// Bitfield of unpicked pieces, not in progress or
    /// completed yet. A set bit is picked, unset is unpicked.
    unpicked: Bitfield,
    /// The current picker in use
    picker: PickerKind,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Block {
    pub index: u32,
    pub offset: u32,
}

/// Pickers act solely as piece picking algorithm.
/// They will select the optimal next piece for a peer,
/// and can be told when a piece is complete(or invalid).
#[derive(Clone, Debug)]
enum PickerKind {
    Rarest(rarest::Picker),
    Sequential(sequential::Picker),
}

/// A downloading block and the peers it has been
/// requested from.
#[derive(Clone, Debug)]
struct Downloading {
    offset: u32,
    completed: bool,
    requested: Vec<Request>,
}

/// A request to a peer and the time it was initiated.
#[derive(Clone, Debug)]
struct Request {
    peer: usize,
    requested_at: time::Instant,
}

const MAX_DUP_REQS: usize = 5;

impl Picker {
    /// Creates a new picker, which will select over
    /// the given pieces. The algorithm used for selection
    /// will vary based on the current swarm state, but
    /// will default to rarest first.
    pub fn new(info: &Info, pieces: &Bitfield) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = rarest::Picker::new(pieces);
        Picker {
            picker: PickerKind::Rarest(picker),
            scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
        }
    }

    /// Returns true if the current picker algorithm is sequential
    pub fn is_sequential(&self) -> bool {
        match self.picker {
            PickerKind::Sequential(_) => true,
            _ => false,
        }
    }

    /// Attempts to select a block for a peer.
    pub fn pick<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        if let Some(b) = self.pick_expired(peer) {
            return Some(b);
        }

        let piece = match self.picker {
            PickerKind::Sequential(ref mut p) => p.pick(peer),
            PickerKind::Rarest(ref mut p) => p.pick(peer),
        };
        piece.and_then(|p| self.pick_piece(p, peer.id())).or_else(
            || {
                self.pick_downloading(peer)
            },
        )
    }

    /// Attempts to pick an expired block
    fn pick_expired<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        // TODO: Use some form of heuristic here to say "we expect to have
        // downloaded some pieces by X, hit the picker with a tick which checks
        // that, flags shit as invalid, and then does a double request
        None
    }

    /// Picks a block from a given piece for a peer
    fn pick_piece(&mut self, piece: u32, id: usize) -> Option<Block> {
        self.downloading.entry(piece).or_insert_with(|| vec![]);
        let dl = self.downloading.get_mut(&piece).unwrap();
        let offset = dl.len() as u32 * 16_384;
        dl.push(Downloading {
            offset,
            completed: false,
            requested: vec![Request::new(id)],
        });

        if dl.len() == self.scale as usize {
            match self.picker {
                PickerKind::Sequential(ref mut p) => p.completed(piece),
                PickerKind::Rarest(ref mut p) => p.completed(piece),
            }
            self.unpicked.set_bit(piece as u64);
        }
        Some(Block {
            index: piece,
            offset,
        })
    }

    /// Attempts to pick an already requested block
    fn pick_downloading<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        for (idx, dl) in &mut self.downloading {
            if peer.pieces().has_bit(*idx as u64) {
                let r = dl.iter_mut()
                    .find(|r| {
                        !r.completed && r.requested.len() < MAX_DUP_REQS &&
                            r.requested.iter().all(|req| req.peer != peer.id())
                    })
                    .map(|r| {
                        r.requested.push(Request::new(peer.id()));
                        Block::new(*idx, r.offset)
                    });
                if r.is_some() {
                    return r;
                }
            }
        }
        None
    }

    /// Marks a block as completed. Returns a result indicating if the block
    /// was actually requested, the success value containing a bool indicating
    /// if the block is complete, and a vector of peers from which the block
    /// was requested(for cancellation).
    pub fn completed(&mut self, b: Block) -> Result<(bool, Vec<usize>), ()> {
        // Find the block in our downloading blocks, mark as true,
        // and extract the current peer list for return.
        let res = self.downloading
            .get_mut(&b.index)
            .and_then(|dl| {
                dl.iter_mut().find(|r| r.offset == b.offset).map(
                    |r| r.complete(),
                )
            })
            .map(|r| r.into_iter().map(|e| e.peer).collect());

        // If we've requested every single block for this piece and they're all complete, remove it
        // and report completion
        let scale = self.scale;
        let complete = self.downloading
            .get_mut(&b.index)
            .map(|r| r.len() as u32 == scale && r.iter().all(|d| d.completed))
            .unwrap_or(false);

        if complete {
            self.downloading.remove(&b.index);
        }

        res.map(|r| (complete, r)).ok_or(())
    }

    /// Invalidates a piece
    pub fn invalidate_piece(&mut self, idx: u32) {
        match self.picker {
            PickerKind::Sequential(ref mut p) => p.incomplete(idx),
            PickerKind::Rarest(ref mut p) => p.incomplete(idx),
        }
        self.unpicked.unset_bit(idx as u64);
    }

    pub fn piece_available(&mut self, idx: u32) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.piece_available(idx);
        }
    }

    pub fn add_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if peer.pieces().complete() {
            self.seeders += 1;
        }
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.add_peer(peer);
        }
    }

    pub fn remove_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.remove_peer(peer);
        }
    }

    /// Alters the picker to sequential/non sequential. If changing
    /// from sequential to non sequential, peer state will need to be loaded
    /// after this.
    pub fn change_picker(&mut self, sequential: bool) {
        self.picker = if sequential {
            PickerKind::Sequential(sequential::Picker::new(&self.unpicked))
        } else {
            PickerKind::Rarest(rarest::Picker::new(&self.unpicked))
        };
        for i in self.downloading.keys() {
            if let PickerKind::Rarest(ref mut p) = self.picker {
                p.dec_avail(*i);
            }
        }
    }

    pub fn refresh_picker(&mut self, pieces: &Bitfield) {
        self.unpicked = pieces.clone();
        self.picker = if self.is_sequential() {
            PickerKind::Sequential(sequential::Picker::new(&self.unpicked))
        } else {
            PickerKind::Rarest(rarest::Picker::new(&self.unpicked))
        };
    }
}

#[cfg(test)]
impl Picker {
    pub fn new_rarest(info: &Info, pieces: &Bitfield) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = rarest::Picker::new(pieces);
        Picker {
            picker: PickerKind::Rarest(picker),
            scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
        }
    }

    pub fn new_sequential(info: &Info, pieces: &Bitfield) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = sequential::Picker::new(pieces);
        Picker {
            picker: PickerKind::Sequential(picker),
            scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
        }
    }
}
impl Block {
    pub fn new(index: u32, offset: u32) -> Block {
        Block { index, offset }
    }
}

impl Request {
    fn new(peer: usize) -> Request {
        Request {
            peer,
            requested_at: time::Instant::now(),
        }
    }
}

impl Downloading {
    fn complete(&mut self) -> Vec<Request> {
        self.completed = true;
        mem::replace(&mut self.requested, Vec::with_capacity(0))
    }
}
<commit_msg>Ensure block requests are removed when peers are removed<commit_after>use std::collections::HashMap;
use std::{mem, time};
use torrent::{Info, Peer, Bitfield};
use control::cio;

mod rarest;
mod sequential;

#[cfg(test)]
mod tests;

#[derive(Clone, Debug)]
pub struct Picker {
    /// Number of blocks per piece
    scale: u32,
    /// Number of detected seeders
    seeders: u16,
    /// Set of pieces which have blocks waiting. These should be prioritized.
    downloading: HashMap<u32, Vec<Downloading>>,
    /// Bitfield of unpicked pieces, not in progress or
    /// completed yet. A set bit is picked, unset is unpicked.
    unpicked: Bitfield,
    /// The current picker in use
    picker: PickerKind,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Block {
    pub index: u32,
    pub offset: u32,
}

/// Pickers act solely as piece picking algorithm.
/// They will select the optimal next piece for a peer,
/// and can be told when a piece is complete(or invalid).
#[derive(Clone, Debug)]
enum PickerKind {
    Rarest(rarest::Picker),
    Sequential(sequential::Picker),
}

/// A downloading block and the peers it has been
/// requested from.
#[derive(Clone, Debug)]
struct Downloading {
    offset: u32,
    completed: bool,
    requested: Vec<Request>,
}

/// A request to a peer and the time it was initiated.
#[derive(Clone, Debug)]
struct Request {
    peer: usize,
    requested_at: time::Instant,
}

const MAX_DUP_REQS: usize = 5;

impl Picker {
    /// Creates a new picker, which will select over
    /// the given pieces. The algorithm used for selection
    /// will vary based on the current swarm state, but
    /// will default to rarest first.
    pub fn new(info: &Info, pieces: &Bitfield) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = rarest::Picker::new(pieces);
        Picker {
            picker: PickerKind::Rarest(picker),
            scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
        }
    }

    /// Returns true if the current picker algorithm is sequential
    pub fn is_sequential(&self) -> bool {
        match self.picker {
            PickerKind::Sequential(_) => true,
            _ => false,
        }
    }

    /// Attempts to select a block for a peer.
    pub fn pick<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        if let Some(b) = self.pick_expired(peer) {
            return Some(b);
        }

        let piece = match self.picker {
            PickerKind::Sequential(ref mut p) => p.pick(peer),
            PickerKind::Rarest(ref mut p) => p.pick(peer),
        };
        piece.and_then(|p| self.pick_piece(p, peer.id())).or_else(
            || {
                self.pick_downloading(peer)
            },
        )
    }

    /// Attempts to pick an expired block
    fn pick_expired<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        // TODO: Use some form of heuristic here to say "we expect to have
        // downloaded some pieces by X, hit the picker with a tick which checks
        // that, flags shit as invalid, and then does a double request
        None
    }

    /// Picks a block from a given piece for a peer
    fn pick_piece(&mut self, piece: u32, id: usize) -> Option<Block> {
        self.downloading.entry(piece).or_insert_with(|| vec![]);
        let dl = self.downloading.get_mut(&piece).unwrap();
        let offset = dl.len() as u32 * 16_384;
        dl.push(Downloading {
            offset,
            completed: false,
            requested: vec![Request::new(id)],
        });

        if dl.len() == self.scale as usize {
            match self.picker {
                PickerKind::Sequential(ref mut p) => p.completed(piece),
                PickerKind::Rarest(ref mut p) => p.completed(piece),
            }
            self.unpicked.set_bit(piece as u64);
        }
        Some(Block {
            index: piece,
            offset,
        })
    }

    /// Attempts to pick an already requested block
    fn pick_downloading<T: cio::CIO>(&mut self, peer: &Peer<T>) -> Option<Block> {
        for (idx, dl) in &mut self.downloading {
            if peer.pieces().has_bit(*idx as u64) {
                let r = dl.iter_mut()
                    .find(|r| {
                        !r.completed && r.requested.len() < MAX_DUP_REQS &&
                            r.requested.iter().all(|req| req.peer != peer.id())
                    })
                    .map(|r| {
                        r.requested.push(Request::new(peer.id()));
                        Block::new(*idx, r.offset)
                    });
                if r.is_some() {
                    return r;
                }
            }
        }
        None
    }

    /// Marks a block as completed. Returns a result indicating if the block
    /// was actually requested, the success value containing a bool indicating
    /// if the block is complete, and a vector of peers from which the block
    /// was requested(for cancellation).
    pub fn completed(&mut self, b: Block) -> Result<(bool, Vec<usize>), ()> {
        // Find the block in our downloading blocks, mark as true,
        // and extract the current peer list for return.
        let res = self.downloading
            .get_mut(&b.index)
            .and_then(|dl| {
                dl.iter_mut().find(|r| r.offset == b.offset).map(
                    |r| r.complete(),
                )
            })
            .map(|r| r.into_iter().map(|e| e.peer).collect());

        // If we've requested every single block for this piece and they're all complete, remove it
        // and report completion
        let scale = self.scale;
        let complete = self.downloading
            .get_mut(&b.index)
            .map(|r| r.len() as u32 == scale && r.iter().all(|d| d.completed))
            .unwrap_or(false);

        if complete {
            self.downloading.remove(&b.index);
        }

        res.map(|r| (complete, r)).ok_or(())
    }

    /// Invalidates a piece
    pub fn invalidate_piece(&mut self, idx: u32) {
        match self.picker {
            PickerKind::Sequential(ref mut p) => p.incomplete(idx),
            PickerKind::Rarest(ref mut p) => p.incomplete(idx),
        }
        self.unpicked.unset_bit(idx as u64);
    }

    pub fn piece_available(&mut self, idx: u32) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.piece_available(idx);
        }
    }

    pub fn add_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if peer.pieces().complete() {
            self.seeders += 1;
        }
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.add_peer(peer);
        }
    }

    pub fn remove_peer<T: cio::CIO>(&mut self, peer: &Peer<T>) {
        if let PickerKind::Rarest(ref mut p) = self.picker {
            p.remove_peer(peer);
        }

        for piece in self.downloading.values_mut() {
            for block in piece {
                block.requested.retain(|req| req.peer != peer.id())
            }
        }
    }

    /// Alters the picker to sequential/non sequential. If changing
    /// from sequential to non sequential, peer state will need to be loaded
    /// after this.
    pub fn change_picker(&mut self, sequential: bool) {
        self.picker = if sequential {
            PickerKind::Sequential(sequential::Picker::new(&self.unpicked))
        } else {
            PickerKind::Rarest(rarest::Picker::new(&self.unpicked))
        };
        for i in self.downloading.keys() {
            if let PickerKind::Rarest(ref mut p) = self.picker {
                p.dec_avail(*i);
            }
        }
    }

    pub fn refresh_picker(&mut self, pieces: &Bitfield) {
        self.unpicked = pieces.clone();
        self.picker = if self.is_sequential() {
            PickerKind::Sequential(sequential::Picker::new(&self.unpicked))
        } else {
            PickerKind::Rarest(rarest::Picker::new(&self.unpicked))
        };
    }
}

#[cfg(test)]
impl Picker {
    pub fn new_rarest(info: &Info, pieces: &Bitfield) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = rarest::Picker::new(pieces);
        Picker {
            picker: PickerKind::Rarest(picker),
            scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
        }
    }

    pub fn new_sequential(info: &Info, pieces: &Bitfield) -> Picker {
        let scale = info.piece_len / 16_384;
        let picker = sequential::Picker::new(pieces);
        Picker {
            picker: PickerKind::Sequential(picker),
            scale,
            seeders: 0,
            unpicked: pieces.clone(),
            downloading: HashMap::new(),
        }
    }
}
impl Block {
    pub fn new(index: u32, offset: u32) -> Block {
        Block { index, offset }
    }
}

impl Request {
    fn new(peer: usize) -> Request {
        Request {
            peer,
            requested_at: time::Instant::now(),
        }
    }
}

impl Downloading {
    fn complete(&mut self) -> Vec<Request> {
        self.completed = true;
        mem::replace(&mut self.requested, Vec::with_capacity(0))
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib::translate::{from_glib_none, ToGlibPtr};
use glib::{to_bool, to_gboolean};
use FFIWidget;
use cast::{GTK_PAPER_SIZE};
use glib;

// FIXME: PaperSize is not a widget nor a GObject -> GBoxed
struct_Widget!(PaperSize);

impl PaperSize {
    pub fn new(name: &str) -> Option<PaperSize> {
        let tmp_pointer = unsafe {
            ffi::gtk_paper_size_new(name.to_glib_none().0)
        };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer as *mut ffi::GtkWidget))
        }
    }

    pub fn new_from_ppd(ppd_name: &str, ppd_display_name: &str, width: f64, height: f64) -> Option<PaperSize> {
        let tmp_pointer = unsafe {
            ffi::gtk_paper_size_new_from_ppd(ppd_name.to_glib_none().0,
                                             ppd_display_name.to_glib_none().0,
                                             width, height)
        };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer as *mut ffi::GtkWidget))
        }
    }

    pub fn new_custom(name: &str, display_name: &str, width: f64, height: f64, unit: ::Unit) -> Option<PaperSize> {
        let tmp_pointer = unsafe {
            ffi::gtk_paper_size_new_custom(name.to_glib_none().0,
                                           display_name.to_glib_none().0,
                                           width, height, unit)
        };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer as *mut ffi::GtkWidget))
        }
    }

    pub fn copy(&self) -> Option<PaperSize> {
        let tmp_pointer = unsafe { ffi::gtk_paper_size_copy(GTK_PAPER_SIZE(self.unwrap_widget())) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(::FFIWidget::wrap_widget(tmp_pointer as *mut ffi::GtkWidget))
        }
    }

    pub fn is_equal(&self, other: &PaperSize) -> bool {
        unsafe { to_bool(ffi::gtk_paper_size_is_equal(GTK_PAPER_SIZE(self.unwrap_widget()), GTK_PAPER_SIZE(other.unwrap_widget()))) }
    }

    pub fn get_paper_sizes(include_custom: bool) -> glib::List<Box<PaperSize>> {
        let tmp = unsafe { ffi::gtk_paper_size_get_paper_sizes(to_gboolean(include_custom))
        };

        if tmp.is_null() {
            glib::List::new()
        } else {
            let old_list : glib::List<*mut ffi::GtkWidget> = glib::GlibContainer::wrap(tmp);
            let mut tmp_vec : glib::List<Box<PaperSize>> = glib::List::new();

            for it in old_list.iter() {
                tmp_vec.append(Box::new(::FFIWidget::wrap_widget(*it)));
            }
            tmp_vec
        }
    }

    pub fn get_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_paper_size_get_name(GTK_PAPER_SIZE(self.unwrap_widget())))
        }
    }

    pub fn get_display_name_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_paper_size_get_display_name(GTK_PAPER_SIZE(self.unwrap_widget())))
        }
    }

    pub fn get_ppd_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_paper_size_get_ppd_name(GTK_PAPER_SIZE(self.unwrap_widget())))
        }
    }

    pub fn get_width(&self, unit: ::Unit) -> f64 {
        unsafe { ffi::gtk_paper_size_get_width(GTK_PAPER_SIZE(self.unwrap_widget()), unit) }
    }

    pub fn get_height(&self, unit: ::Unit) -> f64 {
        unsafe { ffi::gtk_paper_size_get_height(GTK_PAPER_SIZE(self.unwrap_widget()), unit) }
    }

    pub fn is_custom(&self) -> bool {
        unsafe { to_bool(ffi::gtk_paper_size_is_custom(GTK_PAPER_SIZE(self.unwrap_widget()))) }
    }

    pub fn set_size(&self, width: f64, height: f64, unit: ::Unit) {
        unsafe { ffi::gtk_paper_size_set_size(GTK_PAPER_SIZE(self.unwrap_widget()), width, height, unit) }
    }

    pub fn get_default_top_margin(&self, unit: ::Unit) -> f64 {
        unsafe { ffi::gtk_paper_size_get_default_top_margin(GTK_PAPER_SIZE(self.unwrap_widget()), unit) }
    }

    pub fn get_default_bottom_margin(&self, unit: ::Unit) -> f64 {
        unsafe { ffi::gtk_paper_size_get_default_bottom_margin(GTK_PAPER_SIZE(self.unwrap_widget()), unit) }
    }

    pub fn get_default_left_margin(&self, unit: ::Unit) -> f64 {
        unsafe { ffi::gtk_paper_size_get_default_left_margin(GTK_PAPER_SIZE(self.unwrap_widget()), unit) }
    }

    pub fn get_default_right_margin(&self, unit: ::Unit) -> f64 {
        unsafe { ffi::gtk_paper_size_get_default_left_margin(GTK_PAPER_SIZE(self.unwrap_widget()), unit) }
    }

    pub fn get_default() -> Option<String> {
        unsafe {
            from_glib_none(
                ffi::gtk_paper_size_get_default())
        }
    }
}

impl Drop for PaperSize {
    fn drop(&mut self) {
        unsafe {
            ffi::gtk_paper_size_free(GTK_PAPER_SIZE(self.unwrap_widget()));
            ::gobject_ffi::g_object_unref(self.pointer as *mut ::libc::c_void);
        }
    }
}

impl Clone for PaperSize {
    fn clone(&self) -> PaperSize {
        let pointer = unsafe {
            ::gobject_ffi::g_object_ref(self.pointer as *mut ::libc::c_void)
        };

        PaperSize {
            pointer: pointer as *mut ffi::GtkWidget
        }
    }
}

impl_TraitWidget!(PaperSize);
<commit_msg>Delete stray module<commit_after><|endoftext|>


<commit_before>extern crate libc;
extern crate rustbox;
extern crate termbox_sys;
extern crate tiny;

use std::fs::File;
use std::io::Read;
use std::mem;
use std::time::Duration;

use rustbox::{RustBox, InitOptions, InputMode, Event, Key};
use termbox_sys::{tb_change_cell, tb_width};

use tiny::tui::msg_area::line::Line;
use tiny::tui::style;

const WIDTH : i32 = 10;
const HEIGHT : i32 = 10;

fn loop_() -> Option<String> {
    let mut line = Line::new();
    {
        let mut text = String::new();
        let mut file = File::open("test/lipsum.txt").unwrap();
        file.read_to_string(&mut text);
        line.add_text(&text, style::USER_MSG);
    }

    let rustbox = RustBox::init(InitOptions {
        input_mode: InputMode::Esc,
        buffer_stderr: false,
    }).unwrap();

    // I'm using select() here to test for signals/interrupts. Namely, SIGWINCH
    // needs to be handled somehow for resizing.

    let mut fd_set : libc::fd_set = unsafe { mem::zeroed() };
    unsafe { libc::FD_SET(0, &mut fd_set); }
    let nfds = 1; // stdin + 1

    loop {
        rustbox.clear();
        line.draw(&rustbox, 0, 0, unsafe { tb_width() });
        rustbox.present();

        let mut fd_set_ = fd_set.clone();
        let ret = unsafe {
            libc::select(nfds,
                         &mut fd_set_,           // read fds
                         std::ptr::null_mut(),   // write fds
                         std::ptr::null_mut(),   // error fds
                         std::ptr::null_mut())   // timeval
        };

        if unsafe { ret == -1 || libc::FD_ISSET(0, &mut fd_set_) } {
            match rustbox.peek_event(Duration::new(0, 0), false) {
                Ok(Event::KeyEvent(Key::Esc)) => {
                    break;
                },

                Ok(Event::KeyEvent(Key::Char(ch))) => {
                    line.add_char(ch);
                }

                Ok(Event::ResizeEvent(width, height)) => {

                }

                _ => {}
            }
        }
    }

    None
}

fn main() {
    loop_().map(|err| println!("{}", err));
}
<commit_msg>update text example for testing:<commit_after>extern crate libc;
extern crate rustbox;
extern crate termbox_sys;
extern crate tiny;

use std::fs::File;
use std::io::Read;
use std::mem;
use std::time::Duration;

use rustbox::{RustBox, InitOptions, InputMode, Event, Key};

use tiny::tui::msg_area::MsgArea;
use tiny::tui::style;

fn loop_() -> Option<String> {
    let rustbox = RustBox::init(InitOptions {
        input_mode: InputMode::Esc,
        buffer_stderr: false,
    }).unwrap();

    let mut msg_area = MsgArea::new(rustbox.width() as i32, rustbox.height() as i32);

    {
        let mut text = String::new();
        let mut file = File::open("test/lipsum.txt").unwrap();
        file.read_to_string(&mut text).unwrap();
        msg_area.add_text(&text.lines().collect::<Vec<&str>>().join(""), &style::USER_MSG_SS);
        msg_area.flush_line();

        for line in text.lines() {
            msg_area.add_text(">>>", &style::TOPIC_SS);
            msg_area.add_text("  ", &style::SERVER_MSG_SS);
            msg_area.add_text(line, &style::SERVER_MSG_SS);
            msg_area.flush_line();
        }
    }

    // I'm using select() here to test for signals/interrupts. Namely, SIGWINCH
    // needs to be handled somehow for resizing.

    let mut fd_set : libc::fd_set = unsafe { mem::zeroed() };
    unsafe { libc::FD_SET(0, &mut fd_set); }
    let nfds = 1; // stdin + 1

    loop {
        rustbox.clear();
        msg_area.draw(&rustbox, 0, 0);
        rustbox.present();

        let mut fd_set_ = fd_set.clone();
        let ret = unsafe {
            libc::select(nfds,
                         &mut fd_set_,           // read fds
                         std::ptr::null_mut(),   // write fds
                         std::ptr::null_mut(),   // error fds
                         std::ptr::null_mut())   // timeval
        };

        if unsafe { ret == -1 || libc::FD_ISSET(0, &mut fd_set_) } {
            match rustbox.peek_event(Duration::new(0, 0), false) {
                Ok(Event::KeyEvent(Key::Esc)) => {
                    break;
                },

                Ok(Event::KeyEvent(Key::Ctrl('p'))) => {
                    msg_area.scroll_up();
                },

                Ok(Event::KeyEvent(Key::Ctrl('n'))) => {
                    msg_area.scroll_down();
                },

                // Ok(Event::KeyEvent(Key::Char(ch))) => {
                // }

                Ok(Event::ResizeEvent(width, height)) => {
                    msg_area.resize(width, height);
                }

                _ => {}
            }
        }
    }

    None
}

fn main() {
    loop_().map(|err| println!("{}", err));
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Enumerations and structs to represent instructions.
//! Shared by the SSA representation and the intermediate representation of the
//! ESIL parser.

use std::fmt;

pub type Address = u64;
pub type WidthSpec = u16;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
// New address struct
pub struct MAddress {
    pub address: u64,
    pub offset: u64,
}

impl MAddress {
    pub fn new(address: u64, offset: u64) -> MAddress {
        MAddress {
            address: address,
            offset: offset,
        }
    }

    pub fn invalid_address() -> MAddress {
        MAddress {
            address: u64::max_value(),
            offset: u64::max_value(),
        }
    }
}

impl fmt::UpperHex for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08X}.{:04}", self.address, self.offset)
    }
}

impl fmt::Display for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:X}", self)
    }
}

impl From<u64> for MAddress {
    fn from(other: u64) -> MAddress {
        MAddress {
            address: other,
            offset: 0,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MArity {
    Zero,
    Unary,
    Binary,
    Ternary,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MOpcode {
    OpAdd,
    OpSub,
    OpMul,
    OpDiv,
    OpMod,
    OpAnd,
    OpOr,
    OpXor,
    OpNot,
    OpEq,
    OpCmp,
    OpGt,
    OpLt,
    OpLsl,
    OpLsr,
    OpIf,
    OpJmp,
    OpCJmp,
    OpCall,
    OpLoad,
    OpStore,
    OpNarrow(WidthSpec),
    OpWiden(WidthSpec),
    OpConst(u64),
    OpNop,
    OpInvalid,
    // If - Then - Else
    OpITE,
}

impl MOpcode {
    pub fn is_binary(&self) -> bool {
        self.arity() == MArity::Binary
    }

    pub fn is_unary(&self) -> bool {
        self.arity() == MArity::Unary
    }

    pub fn arity(&self) -> MArity {
        self.info().1
    }

    pub fn to_string(&self) -> String {
        self.info().0
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            MOpcode::OpAdd |
            MOpcode::OpMul |
            MOpcode::OpAnd |
            MOpcode::OpOr |
            MOpcode::OpXor |
            MOpcode::OpCmp |
            MOpcode::OpGt |
            MOpcode::OpLt => true,
            _ => false,
        }
    }

    pub fn has_sideeffects(&self) -> bool {
        match *self {
            MOpcode::OpStore |
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpCall |
            MOpcode::OpITE => true,
            _ => false,
        }
    }

    pub fn allowed_in_ssa(&self) -> bool {
        match *self {
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpNop |
            MOpcode::OpITE |
            MOpcode::OpInvalid => false,
            _ => true,
        }
    }

    fn info(&self) -> (String, MArity) {
        match *self {
            MOpcode::OpAdd => ("OpAdd".to_owned(), MArity::Binary),
            MOpcode::OpSub => ("OpSub".to_owned(), MArity::Binary),
            MOpcode::OpMul => ("OpMul".to_owned(), MArity::Binary),
            MOpcode::OpDiv => ("OpDiv".to_owned(), MArity::Binary),
            MOpcode::OpMod => ("OpMod".to_owned(), MArity::Binary),
            MOpcode::OpAnd => ("OpAnd".to_owned(), MArity::Binary),
            MOpcode::OpOr => ("OpOr".to_owned(), MArity::Binary),
            MOpcode::OpXor => ("OpXor".to_owned(), MArity::Binary),
            MOpcode::OpNot => ("OpNot".to_owned(), MArity::Unary),
            MOpcode::OpEq => ("OpEq".to_owned(), MArity::Binary),
            MOpcode::OpCmp => ("OpCmp".to_owned(), MArity::Binary),
            MOpcode::OpGt => ("OpGt".to_owned(), MArity::Binary),
            MOpcode::OpLt => ("OpLt".to_owned(), MArity::Binary),
            MOpcode::OpLsl => ("OpLsl".to_owned(), MArity::Binary),
            MOpcode::OpLsr => ("OpLsr".to_owned(), MArity::Binary),
            MOpcode::OpIf => ("OpIf".to_owned(), MArity::Unary),
            MOpcode::OpLoad => ("OpLoad".to_owned(), MArity::Binary),
            MOpcode::OpStore => ("OpStore".to_owned(), MArity::Binary),
            MOpcode::OpNarrow(_) => ("OpNarrow".to_owned(), MArity::Unary),
            MOpcode::OpWiden(_) => ("OpWiden".to_owned(), MArity::Unary),
            MOpcode::OpJmp => ("OpJmp".to_owned(), MArity::Unary),
            MOpcode::OpCJmp => ("OpJmpIf".to_owned(), MArity::Binary),
            MOpcode::OpCall => ("OpCall".to_owned(), MArity::Unary),
            MOpcode::OpConst(c) => (format!("OpCost({})", c), MArity::Zero),
            MOpcode::OpNop => ("OpNop".to_owned(), MArity::Zero),
            MOpcode::OpInvalid => ("OpInvalid".to_owned(), MArity::Zero),
            MOpcode::OpITE => ("ITE".to_owned(), MArity::Ternary),
        }
    }
}

impl fmt::Display for MOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}
<commit_msg>OpStory should be ternary<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Enumerations and structs to represent instructions.
//! Shared by the SSA representation and the intermediate representation of the
//! ESIL parser.

use std::fmt;

pub type Address = u64;
pub type WidthSpec = u16;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
// New address struct
pub struct MAddress {
    pub address: u64,
    pub offset: u64,
}

impl MAddress {
    pub fn new(address: u64, offset: u64) -> MAddress {
        MAddress {
            address: address,
            offset: offset,
        }
    }

    pub fn invalid_address() -> MAddress {
        MAddress {
            address: u64::max_value(),
            offset: u64::max_value(),
        }
    }
}

impl fmt::UpperHex for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08X}.{:04}", self.address, self.offset)
    }
}

impl fmt::Display for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:X}", self)
    }
}

impl From<u64> for MAddress {
    fn from(other: u64) -> MAddress {
        MAddress {
            address: other,
            offset: 0,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MArity {
    Zero,
    Unary,
    Binary,
    Ternary,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MOpcode {
    OpAdd,
    OpSub,
    OpMul,
    OpDiv,
    OpMod,
    OpAnd,
    OpOr,
    OpXor,
    OpNot,
    OpEq,
    OpCmp,
    OpGt,
    OpLt,
    OpLsl,
    OpLsr,
    OpIf,
    OpJmp,
    OpCJmp,
    OpCall,
    OpLoad,
    OpStore,
    OpNarrow(WidthSpec),
    OpWiden(WidthSpec),
    OpConst(u64),
    OpNop,
    OpInvalid,
    // If - Then - Else
    OpITE,
}

impl MOpcode {
    pub fn is_binary(&self) -> bool {
        self.arity() == MArity::Binary
    }

    pub fn is_unary(&self) -> bool {
        self.arity() == MArity::Unary
    }

    pub fn arity(&self) -> MArity {
        self.info().1
    }

    pub fn to_string(&self) -> String {
        self.info().0
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            MOpcode::OpAdd |
            MOpcode::OpMul |
            MOpcode::OpAnd |
            MOpcode::OpOr |
            MOpcode::OpXor |
            MOpcode::OpCmp |
            MOpcode::OpGt |
            MOpcode::OpLt => true,
            _ => false,
        }
    }

    pub fn has_sideeffects(&self) -> bool {
        match *self {
            MOpcode::OpStore |
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpCall |
            MOpcode::OpITE => true,
            _ => false,
        }
    }

    pub fn allowed_in_ssa(&self) -> bool {
        match *self {
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpNop |
            MOpcode::OpITE |
            MOpcode::OpInvalid => false,
            _ => true,
        }
    }

    fn info(&self) -> (String, MArity) {
        match *self {
            MOpcode::OpAdd => ("OpAdd".to_owned(), MArity::Binary),
            MOpcode::OpSub => ("OpSub".to_owned(), MArity::Binary),
            MOpcode::OpMul => ("OpMul".to_owned(), MArity::Binary),
            MOpcode::OpDiv => ("OpDiv".to_owned(), MArity::Binary),
            MOpcode::OpMod => ("OpMod".to_owned(), MArity::Binary),
            MOpcode::OpAnd => ("OpAnd".to_owned(), MArity::Binary),
            MOpcode::OpOr => ("OpOr".to_owned(), MArity::Binary),
            MOpcode::OpXor => ("OpXor".to_owned(), MArity::Binary),
            MOpcode::OpNot => ("OpNot".to_owned(), MArity::Unary),
            MOpcode::OpEq => ("OpEq".to_owned(), MArity::Binary),
            MOpcode::OpCmp => ("OpCmp".to_owned(), MArity::Binary),
            MOpcode::OpGt => ("OpGt".to_owned(), MArity::Binary),
            MOpcode::OpLt => ("OpLt".to_owned(), MArity::Binary),
            MOpcode::OpLsl => ("OpLsl".to_owned(), MArity::Binary),
            MOpcode::OpLsr => ("OpLsr".to_owned(), MArity::Binary),
            MOpcode::OpIf => ("OpIf".to_owned(), MArity::Unary),
            MOpcode::OpLoad => ("OpLoad".to_owned(), MArity::Binary),
            MOpcode::OpStore => ("OpStore".to_owned(), MArity::Ternary),
            MOpcode::OpNarrow(_) => ("OpNarrow".to_owned(), MArity::Unary),
            MOpcode::OpWiden(_) => ("OpWiden".to_owned(), MArity::Unary),
            MOpcode::OpJmp => ("OpJmp".to_owned(), MArity::Unary),
            MOpcode::OpCJmp => ("OpJmpIf".to_owned(), MArity::Binary),
            MOpcode::OpCall => ("OpCall".to_owned(), MArity::Unary),
            MOpcode::OpConst(c) => (format!("OpCost({})", c), MArity::Zero),
            MOpcode::OpNop => ("OpNop".to_owned(), MArity::Zero),
            MOpcode::OpInvalid => ("OpInvalid".to_owned(), MArity::Zero),
            MOpcode::OpITE => ("ITE".to_owned(), MArity::Ternary),
        }
    }
}

impl fmt::Display for MOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}
<|endoftext|>