<commit_before>use rustc_target::spec::{HasTargetSpec, Target};

use cranelift_module::Module;

use crate::prelude::*;

pub fn mir_var(loc: Local) -> Variable {
    Variable::with_u32(loc.index() as u32)
}

pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
    match tcx.data_layout.pointer_size.bits() {
        16 => types::I16,
        32 => types::I32,
        64 => types::I64,
        bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
    }
}

pub fn clif_type_from_ty<'tcx>(
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<types::Type> {
    Some(match ty.sty {
        ty::Bool => types::I8,
        ty::Uint(size) => match size {
            UintTy::U8 => types::I8,
            UintTy::U16 => types::I16,
            UintTy::U32 => types::I32,
            UintTy::U64 => types::I64,
            UintTy::U128 => types::I128,
            UintTy::Usize => pointer_ty(tcx),
        },
        ty::Int(size) => match size {
            IntTy::I8 => types::I8,
            IntTy::I16 => types::I16,
            IntTy::I32 => types::I32,
            IntTy::I64 => types::I64,
            IntTy::I128 => types::I128,
            IntTy::Isize => pointer_ty(tcx),
        },
        ty::Char => types::I32,
        ty::Float(size) => match size {
            FloatTy::F32 => types::F32,
            FloatTy::F64 => types::F64,
        },
        ty::FnPtr(_) => pointer_ty(tcx),
        ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
            if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
                pointer_ty(tcx)
            } else {
                return None;
            }
        }
        ty::Param(_) => bug!("ty param {:?}", ty),
        _ => return None,
    })
}

pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: Value) -> Value {
    let lhs_ty = bcx.func.dfg.value_type(lhs);
    let rhs_ty = bcx.func.dfg.value_type(rhs);
    assert_eq!(lhs_ty, rhs_ty);
    if lhs_ty == types::I8 || lhs_ty == types::I16 {
        // FIXME workaround for missing enocding for select.i8
        let lhs = bcx.ins().uextend(types::I32, lhs);
        let rhs = bcx.ins().uextend(types::I32, rhs);
        let res = bcx.ins().select(cond, lhs, rhs);
        bcx.ins().ireduce(lhs_ty, res)
    } else {
        bcx.ins().select(cond, lhs, rhs)
    }
}

pub fn clif_intcast<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    val: Value,
    to: Type,
    signed: bool,
) -> Value {
    let from = fx.bcx.func.dfg.value_type(val);
    if from == to {
        return val;
    }
    match (from, to) {
        // equal
        (_, _) if from == to => val,

        // extend
        (_, types::I128) => {
            let wider = if from == types::I64 {
                val
            } else if signed {
                fx.bcx.ins().sextend(types::I64, val)
            } else {
                fx.bcx.ins().uextend(types::I64, val)
            };
            let zero = fx.bcx.ins().iconst(types::I64, 0);
            fx.bcx.ins().iconcat(wider, zero)
        }
        (_, _) if to.wider_or_equal(from) => {
            if signed {
                fx.bcx.ins().sextend(to, val)
            } else {
                fx.bcx.ins().uextend(to, val)
            }
        }

        // reduce
        (types::I128, _) => {
            let (lsb, _msb) = fx.bcx.ins().isplit(val);
            if to == types::I64 {
                lsb
            } else {
                fx.bcx.ins().ireduce(to, lsb)
            }
        }
        (_, _) => {
            fx.bcx.ins().ireduce(to, val)
        }
    }
}

pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
    // FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
    pub tcx: TyCtxt<'tcx>,
    pub module: &'a mut Module<B>,
    pub pointer_type: Type, // Cached from module

    pub instance: Instance<'tcx>,
    pub mir: &'tcx Body<'tcx>,

    pub bcx: FunctionBuilder<'a>,
    pub ebb_map: HashMap<BasicBlock, Ebb>,
    pub local_map: HashMap<Local, CPlace<'tcx>>,

    pub clif_comments: crate::pretty_clif::CommentWriter,
    pub constants: &'a mut crate::constant::ConstantCx,
    pub caches: &'a mut Caches<'tcx>,
    pub source_info_set: indexmap::IndexSet<SourceInfo>,
}

impl<'a, 'tcx: 'a, B: Backend> LayoutOf for FunctionCx<'a, 'tcx, B> {
    type Ty = Ty<'tcx>;
    type TyLayout = TyLayout<'tcx>;

    fn layout_of(&self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
        let ty = self.monomorphize(&ty);
        self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
        self.tcx
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for FunctionCx<'a, 'tcx, B> {
    fn data_layout(&self) -> &layout::TargetDataLayout {
        &self.tcx.data_layout
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasParamEnv<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn param_env(&self) -> ParamEnv<'tcx> {
        ParamEnv::reveal_all()
    }
}

impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for FunctionCx<'a, 'tcx, B> {
    fn target_spec(&self) -> &Target {
        &self.tcx.sess.target.target
    }
}

impl<'a, 'tcx, B: Backend> BackendTypes for FunctionCx<'a, 'tcx, B> {
    type Value = Value;
    type BasicBlock = Ebb;
    type Type = Type;
    type Funclet = !;
    type DIScope = !;
}

impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
    pub fn monomorphize<T>(&self, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        self.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            value,
        )
    }

    pub fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
        clif_type_from_ty(self.tcx, self.monomorphize(&ty))
    }

    pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
        *self.ebb_map.get(&bb).unwrap()
    }

    pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
        *self.local_map.get(&local).unwrap()
    }

    pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
        let (index, _) = self.source_info_set.insert_full(source_info);
        self.bcx.set_srcloc(SourceLoc::new(index as u32));
    }
}
<commit_msg>Remove unnecessary if statement<commit_after>use rustc_target::spec::{HasTargetSpec, Target};

use cranelift_module::Module;

use crate::prelude::*;

pub fn mir_var(loc: Local) -> Variable {
    Variable::with_u32(loc.index() as u32)
}

pub fn pointer_ty(tcx: TyCtxt) -> types::Type {
    match tcx.data_layout.pointer_size.bits() {
        16 => types::I16,
        32 => types::I32,
        64 => types::I64,
        bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits),
    }
}

pub fn clif_type_from_ty<'tcx>(
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<types::Type> {
    Some(match ty.sty {
        ty::Bool => types::I8,
        ty::Uint(size) => match size {
            UintTy::U8 => types::I8,
            UintTy::U16 => types::I16,
            UintTy::U32 => types::I32,
            UintTy::U64 => types::I64,
            UintTy::U128 => types::I128,
            UintTy::Usize => pointer_ty(tcx),
        },
        ty::Int(size) => match size {
            IntTy::I8 => types::I8,
            IntTy::I16 => types::I16,
            IntTy::I32 => types::I32,
            IntTy::I64 => types::I64,
            IntTy::I128 => types::I128,
            IntTy::Isize => pointer_ty(tcx),
        },
        ty::Char => types::I32,
        ty::Float(size) => match size {
            FloatTy::F32 => types::F32,
            FloatTy::F64 => types::F64,
        },
        ty::FnPtr(_) => pointer_ty(tcx),
        ty::RawPtr(TypeAndMut { ty, mutbl: _ }) | ty::Ref(_, ty, _) => {
            if ty.is_sized(tcx.at(DUMMY_SP), ParamEnv::reveal_all()) {
                pointer_ty(tcx)
            } else {
                return None;
            }
        }
        ty::Param(_) => bug!("ty param {:?}", ty),
        _ => return None,
    })
}

pub fn codegen_select(bcx: &mut FunctionBuilder, cond: Value, lhs: Value, rhs: Value) -> Value {
    let lhs_ty = bcx.func.dfg.value_type(lhs);
    let rhs_ty = bcx.func.dfg.value_type(rhs);
    assert_eq!(lhs_ty, rhs_ty);
    if lhs_ty == types::I8 || lhs_ty == types::I16 {
        // FIXME workaround for missing enocding for select.i8
        let lhs = bcx.ins().uextend(types::I32, lhs);
        let rhs = bcx.ins().uextend(types::I32, rhs);
        let res = bcx.ins().select(cond, lhs, rhs);
        bcx.ins().ireduce(lhs_ty, res)
    } else {
        bcx.ins().select(cond, lhs, rhs)
    }
}

pub fn clif_intcast<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    val: Value,
    to: Type,
    signed: bool,
) -> Value {
    let from = fx.bcx.func.dfg.value_type(val);
    match (from, to) {
        // equal
        (_, _) if from == to => val,

        // extend
        (_, types::I128) => {
            let wider = if from == types::I64 {
                val
            } else if signed {
                fx.bcx.ins().sextend(types::I64, val)
            } else {
                fx.bcx.ins().uextend(types::I64, val)
            };
            let zero = fx.bcx.ins().iconst(types::I64, 0);
            fx.bcx.ins().iconcat(wider, zero)
        }
        (_, _) if to.wider_or_equal(from) => {
            if signed {
                fx.bcx.ins().sextend(to, val)
            } else {
                fx.bcx.ins().uextend(to, val)
            }
        }

        // reduce
        (types::I128, _) => {
            let (lsb, _msb) = fx.bcx.ins().isplit(val);
            if to == types::I64 {
                lsb
            } else {
                fx.bcx.ins().ireduce(to, lsb)
            }
        }
        (_, _) => {
            fx.bcx.ins().ireduce(to, val)
        }
    }
}

pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
    // FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
    pub tcx: TyCtxt<'tcx>,
    pub module: &'a mut Module<B>,
    pub pointer_type: Type, // Cached from module

    pub instance: Instance<'tcx>,
    pub mir: &'tcx Body<'tcx>,

    pub bcx: FunctionBuilder<'a>,
    pub ebb_map: HashMap<BasicBlock, Ebb>,
    pub local_map: HashMap<Local, CPlace<'tcx>>,

    pub clif_comments: crate::pretty_clif::CommentWriter,
    pub constants: &'a mut crate::constant::ConstantCx,
    pub caches: &'a mut Caches<'tcx>,
    pub source_info_set: indexmap::IndexSet<SourceInfo>,
}

impl<'a, 'tcx: 'a, B: Backend> LayoutOf for FunctionCx<'a, 'tcx, B> {
    type Ty = Ty<'tcx>;
    type TyLayout = TyLayout<'tcx>;

    fn layout_of(&self, ty: Ty<'tcx>) -> TyLayout<'tcx> {
        let ty = self.monomorphize(&ty);
        self.tcx.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap()
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasTyCtxt<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
        self.tcx
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasDataLayout for FunctionCx<'a, 'tcx, B> {
    fn data_layout(&self) -> &layout::TargetDataLayout {
        &self.tcx.data_layout
    }
}

impl<'a, 'tcx, B: Backend + 'a> layout::HasParamEnv<'tcx> for FunctionCx<'a, 'tcx, B> {
    fn param_env(&self) -> ParamEnv<'tcx> {
        ParamEnv::reveal_all()
    }
}

impl<'a, 'tcx, B: Backend + 'a> HasTargetSpec for FunctionCx<'a, 'tcx, B> {
    fn target_spec(&self) -> &Target {
        &self.tcx.sess.target.target
    }
}

impl<'a, 'tcx, B: Backend> BackendTypes for FunctionCx<'a, 'tcx, B> {
    type Value = Value;
    type BasicBlock = Ebb;
    type Type = Type;
    type Funclet = !;
    type DIScope = !;
}

impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
    pub fn monomorphize<T>(&self, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        self.tcx.subst_and_normalize_erasing_regions(
            self.instance.substs,
            ty::ParamEnv::reveal_all(),
            value,
        )
    }

    pub fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
        clif_type_from_ty(self.tcx, self.monomorphize(&ty))
    }

    pub fn get_ebb(&self, bb: BasicBlock) -> Ebb {
        *self.ebb_map.get(&bb).unwrap()
    }

    pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> {
        *self.local_map.get(&local).unwrap()
    }

    pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
        let (index, _) = self.source_info_set.insert_full(source_info);
        self.bcx.set_srcloc(SourceLoc::new(index as u32));
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use clap::{App, Arg};
use toml;
use rustc_serialize::Decodable;
use rr_result::{RrResult, err_message, rr_error_message};
use version_kind::VersionKind;
use utils::map_file;
use cargo_proj::CargoProj;

/// The configuration used to run `rusty-release`.
#[derive(Debug)]
pub struct Config {
    /// which part of the project version should be incremented
    pub version_kind: VersionKind,

    /// start directory for the search of the 'Cargo.toml'
    pub start_dir: PathBuf,

    /// publish to crates.io
    pub cargo_publish: bool,

    /// push to git remote repository
    pub git_push: bool,

    /// string template for the commit message
    commit_message: String,

    /// string template for the tag name
    tag_name: String,

    /// the editor command, used for opening of the changelog
    editor: String
}

/// Helper macro to apply the settings from ConfigFromFile to Config
macro_rules! config {
    ( $file_config:ident, [ $( $field_name:ident ),* ]) => {{
        let mut config = try!(Config::default());
        $(
            if let Some(f) = $file_config.$field_name {
                config.$field_name = f;
            }
        )*

        config
    }}
}

impl Config {
   pub fn from_file_and_command_args() -> RrResult<Config> {
       let matches = try!(App::new("rusty-release")
           .about("Make a release for a cargo project")
           .version(crate_version!())
           .author("Daniel Trstenjak <daniel.trstenjak@gmail.com>")
           .arg_from_usage("<VERSION_KIND> 'Which version number gets increased (major, minor or patch)'")
           .arg(Arg::with_name("start-dir")
                .short("s")
                .long("start-dir")
                .value_names(&["DIR"])
                .help("Start directory for the search of the Cargo.toml (default: current working directory)")
                .takes_value(true))
           .arg_from_usage("-n --no-cargo-publish 'Do not publish to crates.io'")
           .arg_from_usage("-N --no-git-push 'Do not push to remote git repository'")
           .get_matches_safe());

       let start_dir = matches.value_of("start-dir")
           .map(PathBuf::from)
           .unwrap_or(try!(env::current_dir()));

       if ! start_dir.is_dir() {
           return err_message(format!("Invalid directory given to '--start-dir': '{}'!", start_dir.display()));
       }

       let mut config = try!(Config::from_file());
       config.version_kind = value_t_or_exit!(matches.value_of("VERSION_KIND"), VersionKind);
       config.start_dir = start_dir;

       if matches.is_present("no-cargo-publish") {
           config.cargo_publish = ! matches.is_present("no-cargo-publish");
       }

       if matches.is_present("no-git-push") {
           config.git_push = ! matches.is_present("no-git-push");
       }

       try!(config.check());
       Ok(config)
   }

   pub fn commit_message(&self, proj: &CargoProj) -> String {
       Template(&self.commit_message).render(proj)
   }

   pub fn tag_name(&self, proj: &CargoProj) -> String {
       Template(&self.tag_name).render(proj)
   }

   pub fn editor(&self) -> Command {
       let editor_and_args = self.editor.split(' ').collect::<Vec<&str>>();
       let mut cmd = Command::new(editor_and_args[0]);
       let args = editor_and_args.iter().skip(1);
       for arg in args {
           cmd.arg(arg);
       }

       cmd
   }

   fn from_file() -> RrResult<Config> {
       let curr_file_config = try!(ConfigFromFile::load_from_current_dir());
       let home_file_config = try!(ConfigFromFile::load_from_home_dir());

       let file_config = match (curr_file_config, home_file_config) {
           (Some(cfc), Some(hfc)) => cfc.combine(&hfc),
           (Some(cfc), None)      => cfc,
           (None     , Some(hfc)) => hfc,
           (None     , None)      => ConfigFromFile::default()
       };

       let config = config!(file_config, [
           cargo_publish,
           git_push,
           commit_message,
           tag_name,
           editor
       ]);

       Ok(config)
   }

   fn default() -> RrResult<Config> {
       Ok(Config {
           version_kind: VersionKind::Patch,
           start_dir: try!(env::current_dir()),
           cargo_publish: true,
           git_push: true,
           commit_message: "<PROJ_NAME> <NEW_VERSION>".to_string(),
           tag_name: "<PROJ_NAME>-<NEW_VERSION>".to_string(),
           editor: "gvim -o".to_string()
       })
   }

   fn check(&self) -> RrResult<()> {
       if self.commit_message.is_empty() {
           return err_message("Invalid, empty commit message!");
       }

       if self.tag_name.is_empty() {
           return err_message("Invalid empty tag name!");
       }

       if self.editor.is_empty() {
           return err_message("Invalid, empty editor command!");
       }

       Ok(())
   }
}

/// Represents a string template that contains placeholders that can be replaced.
/// Currently only the placeholders '<PROJ_NAME>' - representing the name of the
/// cargo project and '<NEW_VERSION>' - representing the version of the release -
/// are supported.
#[derive(Debug)]
struct Template<'a>(&'a str);

impl<'a> Template<'a> {
    pub fn render(&self, proj: &CargoProj) -> String {
        self.0.replace("<PROJ_NAME>", &proj.name().to_string())
            .replace("<NEW_VERSION>", &proj.version().to_string())
    }
}

/// Represents the data from a `.rusty-release.toml` configuration file.
#[derive(RustcDecodable, Debug, Default)]
struct ConfigFromFile {
    pub cargo_publish: Option<bool>,
    pub git_push: Option<bool>,
    pub commit_message: Option<String>,
    pub tag_name: Option<String>,
    pub editor: Option<String>
}

impl ConfigFromFile {
    fn load_from_current_dir() -> RrResult<Option<ConfigFromFile>> {
        let path = try!(env::current_dir()).join(config_file_name());
        if ! path.is_file() {
            return Ok(None);
        }

        Ok(Some(try!(ConfigFromFile::load_from_file(&path))))
    }

    fn load_from_home_dir() -> RrResult<Option<ConfigFromFile>> {
        if let Some(path) = env::home_dir().map(|d| d.join(config_file_name())) {
            if path.is_file() {
                return Ok(Some(try!(ConfigFromFile::load_from_file(&path))));
            }
        }

        Ok(None)
    }

    fn load_from_file(path: &Path) -> RrResult<ConfigFromFile> {
        map_file(path, |contents| {
            let mut parser = toml::Parser::new(&contents);
            let value = try!(parser.parse()
                .ok_or_else(|| rr_error_message(format!("Couldn't parse toml file '{}': {:?}",
                                                        path.display(), parser.errors))));

            let mut decoder = toml::Decoder::new(toml::Value::Table(value));
            Ok(try!(ConfigFromFile::decode(&mut decoder)))
        })
    }

    fn combine(&self, other: &ConfigFromFile) -> ConfigFromFile {
        ConfigFromFile {
            cargo_publish: self.cargo_publish.or(other.cargo_publish),
            git_push: self.git_push.or(other.git_push),
            commit_message: self.commit_message.as_ref().or(other.commit_message.as_ref()).cloned(),
            tag_name: self.tag_name.as_ref().or(other.tag_name.as_ref()).cloned(),
            editor: self.editor.as_ref().or(other.editor.as_ref()).cloned()
        }
    }
}

fn config_file_name() -> &'static str {
    ".rusty-release.toml"
}
<commit_msg>Remove unnecessary pub declarations<commit_after>use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use clap::{App, Arg};
use toml;
use rustc_serialize::Decodable;
use rr_result::{RrResult, err_message, rr_error_message};
use version_kind::VersionKind;
use utils::map_file;
use cargo_proj::CargoProj;

/// The configuration used to run `rusty-release`.
#[derive(Debug)]
pub struct Config {
    /// which part of the project version should be incremented
    pub version_kind: VersionKind,

    /// start directory for the search of the 'Cargo.toml'
    pub start_dir: PathBuf,

    /// publish to crates.io
    pub cargo_publish: bool,

    /// push to git remote repository
    pub git_push: bool,

    /// string template for the commit message
    commit_message: String,

    /// string template for the tag name
    tag_name: String,

    /// the editor command, used for opening of the changelog
    editor: String
}

/// Helper macro to apply the settings from ConfigFromFile to Config
macro_rules! config {
    ( $file_config:ident, [ $( $field_name:ident ),* ]) => {{
        let mut config = try!(Config::default());
        $(
            if let Some(f) = $file_config.$field_name {
                config.$field_name = f;
            }
        )*

        config
    }}
}

impl Config {
   pub fn from_file_and_command_args() -> RrResult<Config> {
       let matches = try!(App::new("rusty-release")
           .about("Make a release for a cargo project")
           .version(crate_version!())
           .author("Daniel Trstenjak <daniel.trstenjak@gmail.com>")
           .arg_from_usage("<VERSION_KIND> 'Which version number gets increased (major, minor or patch)'")
           .arg(Arg::with_name("start-dir")
                .short("s")
                .long("start-dir")
                .value_names(&["DIR"])
                .help("Start directory for the search of the Cargo.toml (default: current working directory)")
                .takes_value(true))
           .arg_from_usage("-n --no-cargo-publish 'Do not publish to crates.io'")
           .arg_from_usage("-N --no-git-push 'Do not push to remote git repository'")
           .get_matches_safe());

       let start_dir = matches.value_of("start-dir")
           .map(PathBuf::from)
           .unwrap_or(try!(env::current_dir()));

       if ! start_dir.is_dir() {
           return err_message(format!("Invalid directory given to '--start-dir': '{}'!", start_dir.display()));
       }

       let mut config = try!(Config::from_file());
       config.version_kind = value_t_or_exit!(matches.value_of("VERSION_KIND"), VersionKind);
       config.start_dir = start_dir;

       if matches.is_present("no-cargo-publish") {
           config.cargo_publish = ! matches.is_present("no-cargo-publish");
       }

       if matches.is_present("no-git-push") {
           config.git_push = ! matches.is_present("no-git-push");
       }

       try!(config.check());
       Ok(config)
   }

   pub fn commit_message(&self, proj: &CargoProj) -> String {
       Template(&self.commit_message).render(proj)
   }

   pub fn tag_name(&self, proj: &CargoProj) -> String {
       Template(&self.tag_name).render(proj)
   }

   pub fn editor(&self) -> Command {
       let editor_and_args = self.editor.split(' ').collect::<Vec<&str>>();
       let mut cmd = Command::new(editor_and_args[0]);
       let args = editor_and_args.iter().skip(1);
       for arg in args {
           cmd.arg(arg);
       }

       cmd
   }

   fn from_file() -> RrResult<Config> {
       let curr_file_config = try!(ConfigFromFile::load_from_current_dir());
       let home_file_config = try!(ConfigFromFile::load_from_home_dir());

       let file_config = match (curr_file_config, home_file_config) {
           (Some(cfc), Some(hfc)) => cfc.combine(&hfc),
           (Some(cfc), None)      => cfc,
           (None     , Some(hfc)) => hfc,
           (None     , None)      => ConfigFromFile::default()
       };

       let config = config!(file_config, [
           cargo_publish,
           git_push,
           commit_message,
           tag_name,
           editor
       ]);

       Ok(config)
   }

   fn default() -> RrResult<Config> {
       Ok(Config {
           version_kind: VersionKind::Patch,
           start_dir: try!(env::current_dir()),
           cargo_publish: true,
           git_push: true,
           commit_message: "<PROJ_NAME> <NEW_VERSION>".to_string(),
           tag_name: "<PROJ_NAME>-<NEW_VERSION>".to_string(),
           editor: "gvim -o".to_string()
       })
   }

   fn check(&self) -> RrResult<()> {
       if self.commit_message.is_empty() {
           return err_message("Invalid, empty commit message!");
       }

       if self.tag_name.is_empty() {
           return err_message("Invalid empty tag name!");
       }

       if self.editor.is_empty() {
           return err_message("Invalid, empty editor command!");
       }

       Ok(())
   }
}

/// Represents a string template that contains placeholders that can be replaced.
/// Currently only the placeholders '<PROJ_NAME>' - representing the name of the
/// cargo project and '<NEW_VERSION>' - representing the version of the release -
/// are supported.
#[derive(Debug)]
struct Template<'a>(&'a str);

impl<'a> Template<'a> {
    fn render(&self, proj: &CargoProj) -> String {
        self.0.replace("<PROJ_NAME>", &proj.name().to_string())
            .replace("<NEW_VERSION>", &proj.version().to_string())
    }
}

/// Represents the data from a `.rusty-release.toml` configuration file.
#[derive(RustcDecodable, Debug, Default)]
struct ConfigFromFile {
    cargo_publish: Option<bool>,
    git_push: Option<bool>,
    commit_message: Option<String>,
    tag_name: Option<String>,
    editor: Option<String>
}

impl ConfigFromFile {
    fn load_from_current_dir() -> RrResult<Option<ConfigFromFile>> {
        let path = try!(env::current_dir()).join(config_file_name());
        if ! path.is_file() {
            return Ok(None);
        }

        Ok(Some(try!(ConfigFromFile::load_from_file(&path))))
    }

    fn load_from_home_dir() -> RrResult<Option<ConfigFromFile>> {
        if let Some(path) = env::home_dir().map(|d| d.join(config_file_name())) {
            if path.is_file() {
                return Ok(Some(try!(ConfigFromFile::load_from_file(&path))));
            }
        }

        Ok(None)
    }

    fn load_from_file(path: &Path) -> RrResult<ConfigFromFile> {
        map_file(path, |contents| {
            let mut parser = toml::Parser::new(&contents);
            let value = try!(parser.parse()
                .ok_or_else(|| rr_error_message(format!("Couldn't parse toml file '{}': {:?}",
                                                        path.display(), parser.errors))));

            let mut decoder = toml::Decoder::new(toml::Value::Table(value));
            Ok(try!(ConfigFromFile::decode(&mut decoder)))
        })
    }

    fn combine(&self, other: &ConfigFromFile) -> ConfigFromFile {
        ConfigFromFile {
            cargo_publish: self.cargo_publish.or(other.cargo_publish),
            git_push: self.git_push.or(other.git_push),
            commit_message: self.commit_message.as_ref().or(other.commit_message.as_ref()).cloned(),
            tag_name: self.tag_name.as_ref().or(other.tag_name.as_ref()).cloned(),
            editor: self.editor.as_ref().or(other.editor.as_ref()).cloned()
        }
    }
}

fn config_file_name() -> &'static str {
    ".rusty-release.toml"
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::env;
use std::fs;
use std::io::{self, Read, Write};
use std::ops::Deref;
use std::path::PathBuf;

use csv;
use csv::index::Indexed;
use rustc_serialize::{Decodable, Decoder};

use CliResult;
use select::{SelectColumns, Selection, NormalSelection};
use util;

#[derive(Clone, Copy, Debug)]
pub struct Delimiter(pub u8);

/// Delimiter represents values that can be passed from the command line that
/// can be used as a field delimiter in CSV data.
///
/// Its purpose is to ensure that the Unicode character given decodes to a
/// valid ASCII character as required by the CSV parser.
impl Delimiter {
    pub fn as_byte(self) -> u8 {
        self.0
    }
}

impl Decodable for Delimiter {
    fn decode<D: Decoder>(d: &mut D) -> Result<Delimiter, D::Error> {
        let c = try!(d.read_str());
        match &*c {
            r"\t" => Ok(Delimiter(b'\t')),
            s => {
                if s.len() != 1 {
                    let msg = format!("Could not convert '{}' to a single \
                                       ASCII character.", s);
                    return Err(d.error(&*msg));
                }
                let c = s.chars().next().unwrap();
                if c.is_ascii() {
                    Ok(Delimiter(c as u8))
                } else {
                    let msg = format!("Could not convert '{}' \
                                       to ASCII delimiter.", c);
                    Err(d.error(&*msg))
                }
            }
        }
    }
}

pub struct Config {
    path: Option<PathBuf>, // None implies <stdin>
    idx_path: Option<PathBuf>,
    select_columns: Option<SelectColumns>,
    delimiter: u8,
    pub no_headers: bool,
    flexible: bool,
    crlf: bool,
}

impl Config {
    pub fn new(path: &Option<String>) -> Config {
        let (path, delim) = match *path {
            None => (None, b','),
            Some(ref s) if s.deref() == "-" => (None, b','),
            Some(ref s) => {
                let path = PathBuf::from(s);
                let delim =
                    if path.extension().map_or(false, |v| v == "tsv") {
                        b'\t'
                    } else {
                        b','
                    };
                (Some(path), delim)
            }
        };
        Config {
            path: path,
            idx_path: None,
            select_columns: None,
            delimiter: delim,
            no_headers: false,
            flexible: false,
            crlf: false,
        }
    }

    pub fn delimiter(mut self, d: Option<Delimiter>) -> Config {
        if let Some(d) = d {
            self.delimiter = d.as_byte();
        }
        self
    }

    pub fn no_headers(mut self, mut yes: bool) -> Config {
        if env::var("XSV_TOGGLE_HEADERS").unwrap_or("0".to_owned()) == "1" {
            yes = !yes;
        }
        self.no_headers = yes;
        self
    }

    pub fn flexible(mut self, yes: bool) -> Config {
        self.flexible = yes;
        self
    }

    pub fn crlf(mut self, yes: bool) -> Config {
        self.crlf = yes;
        self
    }

    pub fn select(mut self, sel_cols: SelectColumns) -> Config {
        self.select_columns = Some(sel_cols);
        self
    }

    pub fn is_std(&self) -> bool {
        self.path.is_none()
    }

    pub fn selection(&self, first_record: &[csv::ByteString])
                    -> Result<Selection, String> {
        match self.select_columns {
            None => Err("Config has no 'SelectColums'. Did you call \
                         Config::select?".to_owned()),
            Some(ref sel) => sel.selection(first_record, !self.no_headers),
        }
    }

    pub fn normal_selection(&self, first_record: &[csv::ByteString])
                    -> Result<NormalSelection, String> {
        self.selection(first_record).map(|sel| sel.normal())
    }

    pub fn write_headers<R: io::Read, W: io::Write>
                        (&self, r: &mut csv::Reader<R>, w: &mut csv::Writer<W>)
                        -> csv::Result<()> {
        if !self.no_headers {
            let r = try!(r.byte_headers());
            if !r.is_empty() {
                try!(w.write(r.into_iter()));
            }
        }
        Ok(())
    }

    pub fn writer(&self)
                 -> io::Result<csv::Writer<Box<io::Write+'static>>> {
        Ok(self.from_writer(try!(self.io_writer())))
    }

    pub fn reader(&self)
                 -> io::Result<csv::Reader<Box<io::Read+'static>>> {
        Ok(self.from_reader(try!(self.io_reader())))
    }

    pub fn reader_file(&self) -> io::Result<csv::Reader<fs::File>> {
        match self.path {
            None => Err(io::Error::new(
                io::ErrorKind::Other, "Cannot use <stdin> here",
            )),
            Some(ref p) => fs::File::open(p).map(|f| self.from_reader(f)),
        }
    }

    pub fn index_files(&self)
           -> io::Result<Option<(csv::Reader<fs::File>, fs::File)>> {
        let (csv_file, idx_file) = match (&self.path, &self.idx_path) {
            (&None, &None) => return Ok(None),
            (&None, &Some(_)) => return Err(io::Error::new(
                io::ErrorKind::Other,
                "Cannot use <stdin> with indexes",
                // Some(format!("index file: {}", p.display()))
            )),
            (&Some(ref p), &None) => {
                // We generally don't want to report an error here, since we're
                // passively trying to find an index.
                let idx_file = match fs::File::open(&util::idx_path(p)) {
                    // TODO: Maybe we should report an error if the file exists
                    // but is not readable.
                    Err(_) => return Ok(None),
                    Ok(f) => f,
                };
                (try!(fs::File::open(p)), idx_file)
            }
            (&Some(ref p), &Some(ref ip)) => {
                (try!(fs::File::open(p)), try!(fs::File::open(ip)))
            }
        };
        // If the CSV data was last modified after the index file was last
        // modified, then return an error and demand the user regenerate the
        // index.
        let data_modified = util::last_modified(&try!(csv_file.metadata()));
        let idx_modified = util::last_modified(&try!(idx_file.metadata()));
        if data_modified > idx_modified {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "The CSV file was modified after the index file. \
                 Please re-create the index.",
                // Some(format!("CSV file: {}, index file: {}",
                             // csv_file.path().unwrap().to_string_lossy(),
                             // idx_file.path().unwrap().to_string_lossy())),
            ));
        }
        let csv_rdr = self.from_reader(csv_file);
        Ok(Some((csv_rdr, idx_file)))
    }

    pub fn indexed(&self)
                  -> CliResult<Option<Indexed<fs::File, fs::File>>> {
        match try!(self.index_files()) {
            None => Ok(None),
            Some((r, i)) => Ok(Some(try!(Indexed::open(r, i)))),
        }
    }

    pub fn io_reader(&self) -> io::Result<Box<io::Read+'static>> {
        Ok(match self.path {
            None => Box::new(io::stdin()),
            Some(ref p) => Box::new(try!(fs::File::open(p))),
        })
    }

    pub fn from_reader<R: Read>(&self, rdr: R) -> csv::Reader<R> {
        csv::Reader::from_reader(rdr)
                    .flexible(self.flexible)
                    .delimiter(self.delimiter)
                    .has_headers(!self.no_headers)
    }

    pub fn io_writer(&self) -> io::Result<Box<io::Write+'static>> {
        Ok(match self.path {
            None => Box::new(io::stdout()),
            Some(ref p) => Box::new(try!(fs::File::create(p))),
        })
    }

    pub fn from_writer<W: io::Write>(&self, wtr: W) -> csv::Writer<W> {
        let term = if self.crlf { csv::RecordTerminator::CRLF }
                   else { csv::RecordTerminator::Any(b'\n') };
        csv::Writer::from_writer(wtr)
                    .flexible(self.flexible)
                    .delimiter(self.delimiter)
                    .record_terminator(term)
    }
}
<commit_msg>fix #15<commit_after>use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::env;
use std::fs;
use std::io::{self, Read, Write};
use std::ops::Deref;
use std::path::PathBuf;

use csv;
use csv::index::Indexed;
use rustc_serialize::{Decodable, Decoder};

use CliResult;
use select::{SelectColumns, Selection, NormalSelection};
use util;

#[derive(Clone, Copy, Debug)]
pub struct Delimiter(pub u8);

/// Delimiter represents values that can be passed from the command line that
/// can be used as a field delimiter in CSV data.
///
/// Its purpose is to ensure that the Unicode character given decodes to a
/// valid ASCII character as required by the CSV parser.
impl Delimiter {
    pub fn as_byte(self) -> u8 {
        self.0
    }
}

impl Decodable for Delimiter {
    fn decode<D: Decoder>(d: &mut D) -> Result<Delimiter, D::Error> {
        let c = try!(d.read_str());
        match &*c {
            r"\t" => Ok(Delimiter(b'\t')),
            s => {
                if s.len() != 1 {
                    let msg = format!("Could not convert '{}' to a single \
                                       ASCII character.", s);
                    return Err(d.error(&*msg));
                }
                let c = s.chars().next().unwrap();
                if c.is_ascii() {
                    Ok(Delimiter(c as u8))
                } else {
                    let msg = format!("Could not convert '{}' \
                                       to ASCII delimiter.", c);
                    Err(d.error(&*msg))
                }
            }
        }
    }
}

pub struct Config {
    path: Option<PathBuf>, // None implies <stdin>
    idx_path: Option<PathBuf>,
    select_columns: Option<SelectColumns>,
    delimiter: u8,
    pub no_headers: bool,
    flexible: bool,
    crlf: bool,
}

impl Config {
    pub fn new(path: &Option<String>) -> Config {
        let (path, delim) = match *path {
            None => (None, b','),
            Some(ref s) if s.deref() == "-" => (None, b','),
            Some(ref s) => {
                let path = PathBuf::from(s);
                let delim =
                    if path.extension().map_or(false, |v| v == "tsv") {
                        b'\t'
                    } else {
                        b','
                    };
                (Some(path), delim)
            }
        };
        Config {
            path: path,
            idx_path: None,
            select_columns: None,
            delimiter: delim,
            no_headers: false,
            flexible: false,
            crlf: false,
        }
    }

    pub fn delimiter(mut self, d: Option<Delimiter>) -> Config {
        if let Some(d) = d {
            self.delimiter = d.as_byte();
        }
        self
    }

    pub fn no_headers(mut self, mut yes: bool) -> Config {
        if env::var("XSV_TOGGLE_HEADERS").unwrap_or("0".to_owned()) == "1" {
            yes = !yes;
        }
        self.no_headers = yes;
        self
    }

    pub fn flexible(mut self, yes: bool) -> Config {
        self.flexible = yes;
        self
    }

    pub fn crlf(mut self, yes: bool) -> Config {
        self.crlf = yes;
        self
    }

    pub fn select(mut self, sel_cols: SelectColumns) -> Config {
        self.select_columns = Some(sel_cols);
        self
    }

    pub fn is_std(&self) -> bool {
        self.path.is_none()
    }

    pub fn selection(&self, first_record: &[csv::ByteString])
                    -> Result<Selection, String> {
        match self.select_columns {
            None => Err("Config has no 'SelectColums'. Did you call \
                         Config::select?".to_owned()),
            Some(ref sel) => sel.selection(first_record, !self.no_headers),
        }
    }

    pub fn normal_selection(&self, first_record: &[csv::ByteString])
                    -> Result<NormalSelection, String> {
        self.selection(first_record).map(|sel| sel.normal())
    }

    pub fn write_headers<R: io::Read, W: io::Write>
                        (&self, r: &mut csv::Reader<R>, w: &mut csv::Writer<W>)
                        -> csv::Result<()> {
        if !self.no_headers {
            let r = try!(r.byte_headers());
            if !r.is_empty() {
                try!(w.write(r.into_iter()));
            }
        }
        Ok(())
    }

    pub fn writer(&self)
                 -> io::Result<csv::Writer<Box<io::Write+'static>>> {
        Ok(self.from_writer(try!(self.io_writer())))
    }

    pub fn reader(&self)
                 -> io::Result<csv::Reader<Box<io::Read+'static>>> {
        Ok(self.from_reader(try!(self.io_reader())))
    }

    pub fn reader_file(&self) -> io::Result<csv::Reader<fs::File>> {
        match self.path {
            None => Err(io::Error::new(
                io::ErrorKind::Other, "Cannot use <stdin> here",
            )),
            Some(ref p) => fs::File::open(p).map(|f| self.from_reader(f)),
        }
    }

    pub fn index_files(&self)
           -> io::Result<Option<(csv::Reader<fs::File>, fs::File)>> {
        let (csv_file, idx_file) = match (&self.path, &self.idx_path) {
            (&None, &None) => return Ok(None),
            (&None, &Some(_)) => return Err(io::Error::new(
                io::ErrorKind::Other,
                "Cannot use <stdin> with indexes",
                // Some(format!("index file: {}", p.display()))
            )),
            (&Some(ref p), &None) => {
                // We generally don't want to report an error here, since we're
                // passively trying to find an index.
                let idx_file = match fs::File::open(&util::idx_path(p)) {
                    // TODO: Maybe we should report an error if the file exists
                    // but is not readable.
                    Err(_) => return Ok(None),
                    Ok(f) => f,
                };
                (try!(fs::File::open(p)), idx_file)
            }
            (&Some(ref p), &Some(ref ip)) => {
                (try!(fs::File::open(p)), try!(fs::File::open(ip)))
            }
        };
        // If the CSV data was last modified after the index file was last
        // modified, then return an error and demand the user regenerate the
        // index.
        let data_modified = util::last_modified(&try!(csv_file.metadata()));
        let idx_modified = util::last_modified(&try!(idx_file.metadata()));
        if data_modified > idx_modified {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "The CSV file was modified after the index file. \
                 Please re-create the index.",
                // Some(format!("CSV file: {}, index file: {}",
                             // csv_file.path().unwrap().to_string_lossy(),
                             // idx_file.path().unwrap().to_string_lossy())),
            ));
        }
        let csv_rdr = self.from_reader(csv_file);
        Ok(Some((csv_rdr, idx_file)))
    }

    pub fn indexed(&self)
                  -> CliResult<Option<Indexed<fs::File, fs::File>>> {
        match try!(self.index_files()) {
            None => Ok(None),
            Some((r, i)) => Ok(Some(try!(Indexed::open(r, i)))),
        }
    }

    pub fn io_reader(&self) -> io::Result<Box<io::Read+'static>> {
        Ok(match self.path {
                None => Box::new(io::stdin()),
                Some(ref p) => {
                    match fs::File::open(p){
                        Ok(x) => Box::new(x),
                        Err(err) => panic!("File at {:?} not found!",p)
                    }
                },
            })
    }

    pub fn from_reader<R: Read>(&self, rdr: R) -> csv::Reader<R> {
        csv::Reader::from_reader(rdr)
                    .flexible(self.flexible)
                    .delimiter(self.delimiter)
                    .has_headers(!self.no_headers)
    }

    pub fn io_writer(&self) -> io::Result<Box<io::Write+'static>> {
        Ok(match self.path {
            None => Box::new(io::stdout()),
            Some(ref p) => Box::new(try!(fs::File::create(p))),
        })
    }

    pub fn from_writer<W: io::Write>(&self, wtr: W) -> csv::Writer<W> {
        let term = if self.crlf { csv::RecordTerminator::CRLF }
                   else { csv::RecordTerminator::Any(b'\n') };
        csv::Writer::from_writer(wtr)
                    .flexible(self.flexible)
                    .delimiter(self.delimiter)
                    .record_terminator(term)
    }
}
<|endoftext|>


<commit_before>use mio_uds::UnixStream;
use mio::Ready;
use libc::{self,pid_t};
use std::io::{Seek,SeekFrom};
use std::fs::File;
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use tempfile::tempfile;
use serde_json;
use nix;
use nix::unistd::*;

#[cfg(target_os = "macos")]
use std::ffi::CString;
#[cfg(target_os = "macos")]
use libc::{c_char,uint32_t,int32_t};
#[cfg(target_os = "macos")]
use std::iter::repeat;
#[cfg(target_os = "macos")]
use std::ptr::null_mut;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::scm_socket::{Listeners,ScmSocket};
use sozu_command::proxy::{ProxyRequest,ProxyResponse};
use sozu::server::Server;
use sozu::metrics;

use util;
use logging;
use command::Worker;

pub fn start_workers(executable_path: String, config: &Config) -> nix::Result<Vec<Worker>> {
  let state = ConfigState::new();
  let mut workers = Vec::new();
  for index in 0..config.worker_count {
    let listeners = Some(Listeners {
      http: Vec::new(),
      tls:  Vec::new(),
      tcp:  Vec::new(),
    });
    match start_worker_process(&index.to_string(), config, executable_path.clone(), &state, listeners) {
      Ok((pid, command, scm)) => {
        let w =  Worker::new(index as u32, pid, command, scm, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config, executable_path, state, listeners) {
    Ok((pid, command, scm)) => {
      let w = Worker::new(id, pid, command, scm, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

pub fn begin_worker_process(fd: i32, scm: i32, configuration_state_fd: i32, id: i32,
  command_buffer_size: usize, max_command_buffer_size: usize) {
  let mut command: Channel<ProxyResponse,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    command_buffer_size,
    max_command_buffer_size
  );

  command.set_nonblocking(false);

  let configuration_state_file = unsafe { File::from_raw_fd(configuration_state_fd) };
  let config_state: ConfigState = serde_json::from_reader(configuration_state_file)
    .expect("could not parse configuration state data");

  let worker_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", worker_config);

  let worker_id = format!("{}-{:02}", "WRK", id);
  logging::setup(worker_id.clone(), &worker_config.log_level,
    &worker_config.log_target, worker_config.log_access_target.as_ref().map(|s| s.as_str()));
  info!("worker {} starting...", id);

  command.set_nonblocking(true);
  let mut command: Channel<ProxyResponse,ProxyRequest> = command.into();
  command.readiness.insert(Ready::readable());

  if let Some(ref metrics) = worker_config.metrics.as_ref() {
    metrics::setup(&metrics.address, worker_id, metrics.tagged_metrics, metrics.prefix.clone());
  }

  let mut server = Server::new_from_config(command, ScmSocket::new(scm), worker_config, config_state);

  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<(pid_t, Channel<ProxyRequest,ProxyResponse>, ScmSocket)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let mut state_file = tempfile().expect("could not create temporary file for configuration state");
  util::disable_close_on_exec(state_file.as_raw_fd());

  serde_json::to_writer(&mut state_file, state).expect("could not write upgrade data to temporary file");
  state_file.seek(SeekFrom::Start(0)).expect("could not seek to beginning of file");

  let (server, client) = UnixStream::pair().unwrap();
  let (scm_server_fd, scm_client) = UnixStream::pair().unwrap();

  let scm_server = ScmSocket::new(scm_server_fd.into_raw_fd());

  util::disable_close_on_exec(client.as_raw_fd());
  util::disable_close_on_exec(scm_client.as_raw_fd());

  let mut command: Channel<Config,ProxyResponse> = Channel::new(
    server,
    config.command_buffer_size,
    config.max_command_buffer_size
  );
  command.set_nonblocking(false);

  info!("{} launching worker", id);
  debug!("executable path is {}", executable_path);
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("{} worker launched: {}", id, child);
      command.write_message(config);
      command.set_nonblocking(true);

      if let Some(l) = listeners {
        info!("sending listeners to new worker: {:?}", l);
        let res = scm_server.send_listeners(&l);
        info!("sent listeners from master: {:?}", res);
        l.close();
      };
      util::disable_close_on_exec(scm_server.fd);

      let command: Channel<ProxyRequest,ProxyResponse> = command.into();
      Ok((child.into(), command, scm_server))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(executable_path)
        .arg("worker")
        .arg("--id")
        .arg(id)
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--scm")
        .arg(scm_client.as_raw_fd().to_string())
        .arg("--configuration-state-fd")
        .arg(state_file.as_raw_fd().to_string())
        .arg("--command-buffer-size")
        .arg(config.command_buffer_size.to_string())
        .arg("--max-command-buffer-size")
        .arg(config.max_command_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> String {
  use std::fs;

  let path         = fs::read_link("/proc/self/exe").expect("/proc/self/exe doesn't exist");
  let mut path_str = path.into_os_string().into_string().expect("Failed to convert PathBuf to String");

  if path_str.ends_with(" (deleted)") {
    // The kernel appends " (deleted)" to the symlink when the original executable has been replaced
    let len = path_str.len();
    path_str.truncate(len - 10)
  }

  path_str
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> String {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path.to_str().expect("failed to convert CString to String").to_string()
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<commit_msg>implement the `get_executable_path` function for freeBSD<commit_after>use mio_uds::UnixStream;
use mio::Ready;
use libc::{self,pid_t};
use std::io::{Seek,SeekFrom};
use std::fs::File;
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use tempfile::tempfile;
use serde_json;
use nix;
use nix::unistd::*;

#[cfg(target_os = "macos")]
use std::ffi::CString;
#[cfg(target_os = "macos")]
use libc::{c_char,uint32_t,int32_t};
#[cfg(target_os = "macos")]
use std::iter::repeat;
#[cfg(target_os = "macos")]
use std::ptr::null_mut;

#[cfg(target_os = "freebsd")]
use std::ffi::c_void;
#[cfg(target_os = "freebsd")]
use std::iter::repeat;
#[cfg(target_os = "freebsd")]
use std::mem::size_of;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::scm_socket::{Listeners,ScmSocket};
use sozu_command::proxy::{ProxyRequest,ProxyResponse};
use sozu::server::Server;
use sozu::metrics;

use util;
use logging;
use command::Worker;

pub fn start_workers(executable_path: String, config: &Config) -> nix::Result<Vec<Worker>> {
  let state = ConfigState::new();
  let mut workers = Vec::new();
  for index in 0..config.worker_count {
    let listeners = Some(Listeners {
      http: Vec::new(),
      tls:  Vec::new(),
      tcp:  Vec::new(),
    });
    match start_worker_process(&index.to_string(), config, executable_path.clone(), &state, listeners) {
      Ok((pid, command, scm)) => {
        let w =  Worker::new(index as u32, pid, command, scm, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config, executable_path, state, listeners) {
    Ok((pid, command, scm)) => {
      let w = Worker::new(id, pid, command, scm, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

pub fn begin_worker_process(fd: i32, scm: i32, configuration_state_fd: i32, id: i32,
  command_buffer_size: usize, max_command_buffer_size: usize) {
  let mut command: Channel<ProxyResponse,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    command_buffer_size,
    max_command_buffer_size
  );

  command.set_nonblocking(false);

  let configuration_state_file = unsafe { File::from_raw_fd(configuration_state_fd) };
  let config_state: ConfigState = serde_json::from_reader(configuration_state_file)
    .expect("could not parse configuration state data");

  let worker_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", worker_config);

  let worker_id = format!("{}-{:02}", "WRK", id);
  logging::setup(worker_id.clone(), &worker_config.log_level,
    &worker_config.log_target, worker_config.log_access_target.as_ref().map(|s| s.as_str()));
  info!("worker {} starting...", id);

  command.set_nonblocking(true);
  let mut command: Channel<ProxyResponse,ProxyRequest> = command.into();
  command.readiness.insert(Ready::readable());

  if let Some(ref metrics) = worker_config.metrics.as_ref() {
    metrics::setup(&metrics.address, worker_id, metrics.tagged_metrics, metrics.prefix.clone());
  }

  let mut server = Server::new_from_config(command, ScmSocket::new(scm), worker_config, config_state);

  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<(pid_t, Channel<ProxyRequest,ProxyResponse>, ScmSocket)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let mut state_file = tempfile().expect("could not create temporary file for configuration state");
  util::disable_close_on_exec(state_file.as_raw_fd());

  serde_json::to_writer(&mut state_file, state).expect("could not write upgrade data to temporary file");
  state_file.seek(SeekFrom::Start(0)).expect("could not seek to beginning of file");

  let (server, client) = UnixStream::pair().unwrap();
  let (scm_server_fd, scm_client) = UnixStream::pair().unwrap();

  let scm_server = ScmSocket::new(scm_server_fd.into_raw_fd());

  util::disable_close_on_exec(client.as_raw_fd());
  util::disable_close_on_exec(scm_client.as_raw_fd());

  let mut command: Channel<Config,ProxyResponse> = Channel::new(
    server,
    config.command_buffer_size,
    config.max_command_buffer_size
  );
  command.set_nonblocking(false);

  info!("{} launching worker", id);
  debug!("executable path is {}", executable_path);
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("{} worker launched: {}", id, child);
      command.write_message(config);
      command.set_nonblocking(true);

      if let Some(l) = listeners {
        info!("sending listeners to new worker: {:?}", l);
        let res = scm_server.send_listeners(&l);
        info!("sent listeners from master: {:?}", res);
        l.close();
      };
      util::disable_close_on_exec(scm_server.fd);

      let command: Channel<ProxyRequest,ProxyResponse> = command.into();
      Ok((child.into(), command, scm_server))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(executable_path)
        .arg("worker")
        .arg("--id")
        .arg(id)
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--scm")
        .arg(scm_client.as_raw_fd().to_string())
        .arg("--configuration-state-fd")
        .arg(state_file.as_raw_fd().to_string())
        .arg("--command-buffer-size")
        .arg(config.command_buffer_size.to_string())
        .arg("--max-command-buffer-size")
        .arg(config.max_command_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> String {
  use std::fs;

  let path         = fs::read_link("/proc/self/exe").expect("/proc/self/exe doesn't exist");
  let mut path_str = path.into_os_string().into_string().expect("Failed to convert PathBuf to String");

  if path_str.ends_with(" (deleted)") {
    // The kernel appends " (deleted)" to the symlink when the original executable has been replaced
    let len = path_str.len();
    path_str.truncate(len - 10)
  }

  path_str
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> String {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path.to_str().expect("failed to convert CString to String").to_string()

    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}

#[cfg(target_os = "freebsd")]
extern "C" {
    // int
    // sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
    // const void *newp, size_t newlen);
    pub fn sysctl(
        name: *const std::os::raw::c_int,
        namelen: std::os::raw::c_uint,
        oldp: *mut c_void,
        oldlenp: *mut usize,
        newp: *const c_void,
        newlen: usize,
    ) -> std::os::raw::c_int;
    // char *
    // realpath(const char * restrict pathname, char * restrict resolved_path);
    pub fn realpath(
        pathname: *const std::os::raw::c_char,
        resolved_path: *mut std::os::raw::c_char,
    ) -> *const std::os::raw::c_char;

}

#[cfg(target_os = "freebsd")]
pub unsafe fn get_executable_path() -> String {
    let mut capacity = 2000;
    let mut path: Vec<u8> = Vec::with_capacity(capacity);
    path.extend(repeat(0).take(capacity));

    // [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
    let mib: Vec<i32> = vec![1, 14, 12, -1];
    let len = mib.len() * size_of::<i32>();
    let element_size = size_of::<i32>();

    let res = sysctl(
        mib.as_ptr(),
        (len / element_size) as u32,
        path.as_mut_ptr() as *mut c_void,
        &mut capacity,
        std::ptr::null() as *const c_void,
        0,
    );
    if res != 0 {
        panic!("Could not retrieve the path of the executable");
    }

    String::from_raw_parts(path.as_mut_ptr(), capacity - 1, path.len())
}
<|endoftext|>


<commit_before>//! Drawing maps and game states on the screen with Glium.
//!
//! The `drawer` module defines types that know how to draw a graph and a game
//! state on the screen using Glium calls.
//!
//! # Coordinate spaces
//!
//! Although rbattle is a 2D game, which simplifies things a lot, it needs to
//! work with a few different coordinate systems. Working from the the most
//! concrete (pixels on the screen) to the abstract (nodes on the graph):
//!
//! - Window coordinates. The window's area is a rectangular matrix of pixels,
//!   with (0,0) at the upper left, and the positive x and y axes pointing to
//!   the right and down.
//!
//! - Normalized device coordinates (NDC). Normalized device coordinates cover
//!   the window in a resolution-independent way. In NDC, (0,0) is the center of
//!   the screen; the positive x and y axes point to the right and up, as is
//!   traditional in mathematics; and the edges of the window are -1 and 1 for
//!   both axes.
//!
//! - Game coordinates: (-1, -1) and (1, 1) are the lower-left and upper-right
//!   coordinates of the overall display of the game. We choose the
//!   transformation between this and NDC to keep the game display fully visible
//!   and centered in the window.
//!
//! - Graph space coordinates: the coordinate system defined by the VisibleGraph
//!   implementation, where nodes' areas fall in the axis-aligned bounding box
//!   between (0,0) and upper_right, where upper_right is what you get from
//!   VisibleGraph::bounds().

use errors::*;
use map::Map;
use state::State;
use math::{compose, scale_transform, translate_transform};
use visible_graph::{GraphPt, VisibleGraph};

use glium::{DrawParameters, Frame, IndexBuffer, Program, Surface, VertexBuffer};
use glium::backend::Facade;
use glium::index::PrimitiveType;
//use glium::vertex::Vertex;

/// A `Drawer` knows how to draw a `State` on a Glium `Frame`.
///
/// A `Drawer` is constructed from a `Map`, and then is given specific `State`
/// values that use that `Map` to draw a complete frame of the game on a Glium
/// `Frame` value, representing one frame of video.
///
/// The `Drawer` is the right place to hold Glium state that persists between
/// frames, like vertex and index buffers for the map.
pub struct Drawer {
    /// Cached information needed to drawing the map, excluding the map itself.
    /// This holds vertex and index buffers, shader programs, transformations,
    /// and the like.
    pub map: MapDrawer
}

impl Drawer {
    pub fn new<G>(display: &Facade, map: &Map<G>) -> Result<Drawer>
        where G: VisibleGraph
    {
        Ok(Drawer {
            map: MapDrawer::new(display, map)?
        })
    }

    pub fn draw<G>(&self, frame: &mut Frame, state: &State<G>) -> Result<()>
        where G: VisibleGraph
    {
        self.map.draw(frame, &state.map)
    }
}

pub struct MapDrawer {
    /// Vertexes of the graph's boundary lines.
    vertices: VertexBuffer<GraphVert>,

    /// Indices for the graph's boundary lines.
    indices: IndexBuffer<u32>,

    /// Transformation from graph space to game space.
    graph_to_game: [[f32; 3]; 3],

    /// The aspect ratio (width / height) of the game rectangle.
    game_aspect: f32,

    /// Shader program for drawing the map.
    program: Program,

    /// Draw parameters for drawing the map.
    draw_params: DrawParameters<'static>
}

impl MapDrawer {
    fn new<G>(display: &Facade, map: &Map<G>) -> Result<MapDrawer>
        where G: VisibleGraph
    {
        let graph = &map.graph;

        // It's a little annoying that we have to do this map to convert GraphPt
        // to GraphVert, but I'd rather do this than a transmute.
        let vertices = graph.endpoints().into_iter()
            .map(|point| GraphVert { point: [point.0, point.1] })
            .collect::<Vec<GraphVert>>();
        let vertices = VertexBuffer::new(display, &vertices)
            .chain_err(|| "building buffer for graph vertices")?;

        let mut indices = Vec::new();
        for node in 0..graph.nodes() {
            for segment in graph.boundary(node) {
                // A boundary line between two nodes will appear twice in the
                // list. Cull out the duplicates by only retaining segments with
                // no node on the other side, or where the node on the other
                // side has a higher number.
                if match segment.neighbor {
                    None => true,
                    Some(neighbor) => node < neighbor
                } {
                    indices.push(segment.line.start as u32);
                    indices.push(segment.line.end as u32);
                }
            }
        }

        let indices = IndexBuffer::new(display, PrimitiveType::LinesList, &indices)
            .chain_err(|| "building buffer for graph indices")?;

        // Compute the transformation from graph space, where points run from
        // (0, 0) to upper_right, to game space, where points run from (-1, -1)
        // to (1,1).
        let GraphPt(width, height) = graph.bounds();
        let game_aspect = width / height;
        let graph_to_game =
            compose(translate_transform(-1.0, -1.0),
                    scale_transform(2.0 / width, 2.0 / height));

        let program = Program::from_source(display,
                                           include_str!("map.vert"),
                                           include_str!("map.frag"),
                                           None)
            .chain_err(|| "compiling map shaders")?;

        let draw_params = DrawParameters {
            line_width: Some(2.0),
            .. Default::default()
        };

        Ok(MapDrawer {
            vertices, indices, game_aspect, graph_to_game, program, draw_params
        })
    }

    /// Draw `map` on `frame`.
    ///
    /// The map `state` uses must be the same map that was passed to
    /// `MapDrawer::new` when this `MapDrawer` was created.
    fn draw<G>(&self, frame: &mut Frame, _map: &Map<G>) -> Result<()>
        where G: VisibleGraph
    {
        // Compute the aspect ratio of the window (the "device"), assuming
        // square pixels.
        let (width, height) = frame.get_dimensions();
        let device_aspect = width as f32 / height as f32;

        // Compute the transformation from game coordinates to normalized device
        // coordinates. Depending on their relative aspect ratios, the game may
        // be centered either vertically or horizontally within the window.
        let game_to_device =
            if device_aspect > self.game_aspect {
                // Window is wider than game. Game centered horizontally.
                scale_transform(self.game_aspect / device_aspect, 1.0)
            } else {
                // Game is wider than window. Game centered vertically.
                scale_transform(1.0, device_aspect / self.game_aspect)
            };

        let graph_to_device = compose(game_to_device, self.graph_to_game);

        frame.draw(&self.vertices, &self.indices, &self.program,
                   &uniform! {
                       graph_to_device: graph_to_device
                   },
                   &self.draw_params)
            .chain_err(|| "drawing map")?;

        Ok(())
    }
}

/// A vertex in Graph space.
#[derive(Copy, Clone, Debug)]
struct GraphVert { point: [f32; 2] }

implement_vertex!(GraphVert, point);
<commit_msg>Add margin.<commit_after>//! Drawing maps and game states on the screen with Glium.
//!
//! The `drawer` module defines types that know how to draw a graph and a game
//! state on the screen using Glium calls.
//!
//! # Coordinate spaces
//!
//! Although rbattle is a 2D game, which simplifies things a lot, it needs to
//! work with a few different coordinate systems. Working from the the most
//! concrete (pixels on the screen) to the abstract (nodes on the graph):
//!
//! - Window coordinates. The window's area is a rectangular matrix of pixels,
//!   with (0,0) at the upper left, and the positive x and y axes pointing to
//!   the right and down.
//!
//! - Normalized device coordinates (NDC). Normalized device coordinates cover
//!   the window in a resolution-independent way. In NDC, (0,0) is the center of
//!   the screen; the positive x and y axes point to the right and up, as is
//!   traditional in mathematics; and the edges of the window are -1 and 1 for
//!   both axes.
//!
//! - Game coordinates: (-1, -1) and (1, 1) are the lower-left and upper-right
//!   coordinates of the overall display of the game. We choose the
//!   transformation between this and NDC to keep the game display fully visible
//!   and centered in the window.
//!
//! - Graph space coordinates: the coordinate system defined by the VisibleGraph
//!   implementation, where nodes' areas fall in the axis-aligned bounding box
//!   between (0,0) and upper_right, where upper_right is what you get from
//!   VisibleGraph::bounds().

use errors::*;
use map::Map;
use state::State;
use math::{compose, scale_transform, translate_transform};
use visible_graph::{GraphPt, VisibleGraph};

use glium::{DrawParameters, Frame, IndexBuffer, Program, Surface, VertexBuffer};
use glium::backend::Facade;
use glium::index::PrimitiveType;
//use glium::vertex::Vertex;

/// A `Drawer` knows how to draw a `State` on a Glium `Frame`.
///
/// A `Drawer` is constructed from a `Map`, and then is given specific `State`
/// values that use that `Map` to draw a complete frame of the game on a Glium
/// `Frame` value, representing one frame of video.
///
/// The `Drawer` is the right place to hold Glium state that persists between
/// frames, like vertex and index buffers for the map.
pub struct Drawer {
    /// Cached information needed to drawing the map, excluding the map itself.
    /// This holds vertex and index buffers, shader programs, transformations,
    /// and the like.
    pub map: MapDrawer
}

impl Drawer {
    pub fn new<G>(display: &Facade, map: &Map<G>) -> Result<Drawer>
        where G: VisibleGraph
    {
        Ok(Drawer {
            map: MapDrawer::new(display, map)?
        })
    }

    pub fn draw<G>(&self, frame: &mut Frame, state: &State<G>) -> Result<()>
        where G: VisibleGraph
    {
        self.map.draw(frame, &state.map)
    }
}

pub struct MapDrawer {
    /// Vertexes of the graph's boundary lines.
    vertices: VertexBuffer<GraphVert>,

    /// Indices for the graph's boundary lines.
    indices: IndexBuffer<u32>,

    /// Transformation from graph space to game space.
    graph_to_game: [[f32; 3]; 3],

    /// The aspect ratio (width / height) of the game rectangle.
    game_aspect: f32,

    /// Shader program for drawing the map.
    program: Program,

    /// Draw parameters for drawing the map.
    draw_params: DrawParameters<'static>
}

impl MapDrawer {
    fn new<G>(display: &Facade, map: &Map<G>) -> Result<MapDrawer>
        where G: VisibleGraph
    {
        let graph = &map.graph;

        // It's a little annoying that we have to do this map to convert GraphPt
        // to GraphVert, but I'd rather do this than a transmute.
        let vertices = graph.endpoints().into_iter()
            .map(|point| GraphVert { point: [point.0, point.1] })
            .collect::<Vec<GraphVert>>();
        let vertices = VertexBuffer::new(display, &vertices)
            .chain_err(|| "building buffer for graph vertices")?;

        let mut indices = Vec::new();
        for node in 0..graph.nodes() {
            for segment in graph.boundary(node) {
                // A boundary line between two nodes will appear twice in the
                // list. Cull out the duplicates by only retaining segments with
                // no node on the other side, or where the node on the other
                // side has a higher number.
                if match segment.neighbor {
                    None => true,
                    Some(neighbor) => node < neighbor
                } {
                    indices.push(segment.line.start as u32);
                    indices.push(segment.line.end as u32);
                }
            }
        }

        let indices = IndexBuffer::new(display, PrimitiveType::LinesList, &indices)
            .chain_err(|| "building buffer for graph indices")?;

        // Compute the transformation from graph space, where points run from
        // (0, 0) to upper_right, to game space, where points run from (-1, -1)
        // to (1,1).
        let GraphPt(width, height) = graph.bounds();
        let game_aspect = width / height;
        let graph_to_game =
            compose(translate_transform(-1.0, -1.0),
                    scale_transform(2.0 / width, 2.0 / height));

        // A little margin inside the window is nice.
        let graph_to_game = compose(scale_transform(0.95, 0.95), graph_to_game);

        let program = Program::from_source(display,
                                           include_str!("map.vert"),
                                           include_str!("map.frag"),
                                           None)
            .chain_err(|| "compiling map shaders")?;

        let draw_params = DrawParameters {
            line_width: Some(2.0),
            .. Default::default()
        };

        Ok(MapDrawer {
            vertices, indices, game_aspect, graph_to_game, program, draw_params
        })
    }

    /// Draw `map` on `frame`.
    ///
    /// The map `state` uses must be the same map that was passed to
    /// `MapDrawer::new` when this `MapDrawer` was created.
    fn draw<G>(&self, frame: &mut Frame, _map: &Map<G>) -> Result<()>
        where G: VisibleGraph
    {
        // Compute the aspect ratio of the window (the "device"), assuming
        // square pixels.
        let (width, height) = frame.get_dimensions();
        let device_aspect = width as f32 / height as f32;

        // Compute the transformation from game coordinates to normalized device
        // coordinates. Depending on their relative aspect ratios, the game may
        // be centered either vertically or horizontally within the window.
        let game_to_device =
            if device_aspect > self.game_aspect {
                // Window is wider than game. Game centered horizontally.
                scale_transform(self.game_aspect / device_aspect, 1.0)
            } else {
                // Game is wider than window. Game centered vertically.
                scale_transform(1.0, device_aspect / self.game_aspect)
            };

        let graph_to_device = compose(game_to_device, self.graph_to_game);

        frame.draw(&self.vertices, &self.indices, &self.program,
                   &uniform! {
                       graph_to_device: graph_to_device
                   },
                   &self.draw_params)
            .chain_err(|| "drawing map")?;

        Ok(())
    }
}

/// A vertex in Graph space.
#[derive(Copy, Clone, Debug)]
struct GraphVert { point: [f32; 2] }

implement_vertex!(GraphVert, point);
<|endoftext|>


<commit_before>use std::fmt;

type OscResult<T> = Result<T, OscError>;

pub enum OscError {
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}

impl fmt::Display for OscError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            _ => write!(f, "{}", "TODO"),
        }
    }
}
<commit_msg>Add String and Read error<commit_after>use std::{fmt, io, string};

type OscResult<T> = Result<T, OscError>;

pub enum OscError {
    StringError(string::FromUtf8Error),
    ReadError(io::Error),
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}

impl fmt::Display for OscError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            _ => write!(f, "{}", "TODO"),
        }
    }
}
<|endoftext|>