<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::{gl, Texture, Sampler};
use super::gl::types::{GLenum, GLuint, GLint, GLfloat, GLsizei, GLvoid};
use tex::*;
use Blob;

fn kind_to_gl(t: ::tex::TextureKind) -> GLenum {
    match t {
        Texture1D => gl::TEXTURE_1D,
        Texture1DArray => gl::TEXTURE_1D_ARRAY,
        Texture2D => gl::TEXTURE_2D,
        Texture2DArray => gl::TEXTURE_2D_ARRAY,
        TextureCube => gl::TEXTURE_CUBE_MAP,
        Texture3D => gl::TEXTURE_3D,
    }
}

fn format_to_gl(t: ::tex::TextureFormat) -> GLenum {
    match t {
        RGB8 => gl::RGB8,
        RGBA8 => gl::RGBA8,
    }
}

fn format_to_glpixel(t: ::tex::TextureFormat) -> GLenum {
    match t {
        RGB8 => gl::RGB,
        RGBA8 => gl::RGBA
    }
}

fn format_to_gltype(t: ::tex::TextureFormat) -> GLenum {
    match t {
        RGB8 | RGBA8 => gl::UNSIGNED_BYTE,
    }
}

/// Create a texture, assuming TexStorage* isn't available.
pub fn make_without_storage(info: ::tex::TextureInfo) -> Texture {
    let name = make_texture(info);

    let fmt = format_to_gl(info.format) as GLint;
    let pix = format_to_glpixel(info.format);
    let typ = format_to_gltype(info.format);

    let kind = kind_to_gl(info.kind);

    unsafe {
        match info.kind {
            Texture1D => {
                gl::TexImage1D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
            Texture1DArray => {
                gl::TexImage2D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    info.height as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
            Texture2D => {
                gl::TexImage2D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    info.height as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
            TextureCube => unimplemented!(),
            Texture2DArray | Texture3D => {
                gl::TexImage3D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    info.height as GLsizei,
                    info.depth as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
        }
    }

    name
}

/// Create a texture, assuming TexStorage is available.
pub fn make_with_storage(info: ::tex::TextureInfo) -> Texture {
    use std::cmp::max;

    fn min(a: u8, b: u8) -> GLint {
        ::std::cmp::min(a, b) as GLint
    }

    fn mip_level1(w: u16) -> u8 {
        ((w as f32).log2() + 1.0) as u8
    }

    fn mip_level2(w: u16, h: u16) -> u8 {
        ((max(w, h) as f32).log2() + 1.0) as u8
    }

    fn mip_level3(w: u16, h: u16, d: u16) -> u8 {
        ((max(w, max(h, d)) as f32).log2() + 1.0) as u8
    }

    let name = make_texture(info);

    let fmt = format_to_gl(info.format);
    let kind = kind_to_gl(info.kind);

    match info.kind {
        Texture1D => {
            gl::TexStorage1D(
                kind,
                min(info.mipmap_range.val1(), mip_level1(info.width)),
                fmt,
                info.width as GLsizei
            );
        },
        Texture1DArray => {
            gl::TexStorage2D(
                kind,
                min(info.mipmap_range.val1(), mip_level1(info.width)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
            );
        },
        Texture2D => {
            gl::TexStorage2D(
                kind,
                min(info.mipmap_range.val1(), mip_level2(info.width, info.height)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
            );
        },
        TextureCube => unimplemented!(),
        Texture2DArray => {
            gl::TexStorage3D(
                kind,
                min(info.mipmap_range.val1(), mip_level2(info.width, info.height)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
                info.depth as GLsizei,
            );
        },
        Texture3D => {
            gl::TexStorage3D(
                kind,
                min(info.mipmap_range.val1(), mip_level3(info.width, info.height, info.depth)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
                info.depth as GLsizei,
            );
        },
    }

    name
}

/// Bind a texture + sampler to a given slot.
pub fn bind_texture(loc: GLuint, tex: Texture, sam: Sampler, info: ::tex::TextureInfo) {
    gl::ActiveTexture(gl::TEXTURE0 + loc as GLenum);
    gl::BindSampler(loc, sam);
    gl::BindTexture(kind_to_gl(info.kind), tex);
}

pub fn update_texture(tex: Texture, img: ::tex::ImageInfo, tex_info: ::tex::TextureInfo,
                      data: Box<Blob + Send>) {
    debug_assert!(img.width as u32 * img.height as u32 * img.depth as u32 == data.get_size() as u32);

    let data = data.get_address() as *const GLvoid;
    let pix = format_to_glpixel(tex_info.format);
    let typ = format_to_gltype(tex_info.format);

    gl::BindTexture(kind_to_gl(tex_info.kind), tex);

    unsafe {
        match tex_info.kind {
            Texture1D => {
                gl::TexSubImage1D(
                    kind_to_gl(tex_info.kind),
                    img.mipmap as GLint,
                    img.xoffset as GLint,
                    img.width as GLint,
                    pix,
                    typ,
                    data,
                );
            },
            Texture1DArray | Texture2D => {
                gl::TexSubImage2D(
                    kind_to_gl(tex_info.kind),
                    img.mipmap as GLint,
                    img.xoffset as GLint,
                    img.yoffset as GLint,
                    img.width as GLint,
                    img.height as GLint,
                    pix,
                    typ,
                    data,
                );
            },
            TextureCube => unimplemented!(),
            Texture2DArray | Texture3D => {
                gl::TexSubImage3D(
                    kind_to_gl(tex_info.kind),
                    img.mipmap as GLint,
                    img.xoffset as GLint,
                    img.yoffset as GLint,
                    img.zoffset as GLint,
                    img.width as GLint,
                    img.height as GLint,
                    img.depth as GLint,
                    pix,
                    typ,
                    data,
                );
            }
        }
    }
}

/// Common texture creation routine, just binds and sets mipmap ranges.
fn make_texture(info: ::tex::TextureInfo) -> Texture {
    let mut name = 0 as Texture;
    unsafe {
        gl::GenTextures(1, &mut name);
    }

    let k = kind_to_gl(info.kind);
    gl::BindTexture(k, name);

    let (base, max) = info.mipmap_range;
    gl::TexParameteri(k, gl::TEXTURE_BASE_LEVEL, base as GLint);
    gl::TexParameteri(k, gl::TEXTURE_MAX_LEVEL, max as GLint);

    name
}

fn wrap_to_gl(w: WrapMode) -> GLenum {
    match w {
        Tile => gl::REPEAT,
        Mirror => gl::MIRRORED_REPEAT,
        Clamp => gl::CLAMP_TO_EDGE
    }
}

pub fn make_sampler(info: ::tex::SamplerInfo) -> Sampler {
    let mut name = 0 as Sampler;
    unsafe {
        gl::GenSamplers(1, &mut name);
    }

    let (min, mag) = match info.filtering {
        Scale => (gl::NEAREST, gl::NEAREST),
        Mipmap => (gl::NEAREST_MIPMAP_NEAREST, gl::NEAREST),
        Bilinear => (gl::LINEAR_MIPMAP_NEAREST, gl::LINEAR),
        Trilinear => (gl::LINEAR_MIPMAP_LINEAR, gl::LINEAR),
        Anisotropic(fac) => {
            gl::SamplerParameterf(name, gl::TEXTURE_MAX_ANISOTROPY_EXT, fac as GLfloat);
            (gl::LINEAR_MIPMAP_LINEAR, gl::LINEAR)
        }
    };

    gl::SamplerParameteri(name, gl::TEXTURE_MIN_FILTER, min as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_MAG_FILTER, mag as GLint);

    let (s, t, r) = info.wrap_mode;
    gl::SamplerParameteri(name, gl::TEXTURE_WRAP_S, wrap_to_gl(s) as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_WRAP_T, wrap_to_gl(t) as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_WRAP_R, wrap_to_gl(r) as GLint);

    gl::SamplerParameterf(name, gl::TEXTURE_LOD_BIAS, info.lod_bias);

    let (base, max) = info.mipmap_range;
    gl::SamplerParameteri(name, gl::TEXTURE_BASE_LEVEL, base as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_MAX_LEVEL, max as GLint);

    name
}
<commit_msg>Remove mipmap level setting, they will be clamped.<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::{gl, Texture, Sampler};
use super::gl::types::{GLenum, GLuint, GLint, GLfloat, GLsizei, GLvoid};
use tex::*;
use Blob;

fn kind_to_gl(t: ::tex::TextureKind) -> GLenum {
    match t {
        Texture1D => gl::TEXTURE_1D,
        Texture1DArray => gl::TEXTURE_1D_ARRAY,
        Texture2D => gl::TEXTURE_2D,
        Texture2DArray => gl::TEXTURE_2D_ARRAY,
        TextureCube => gl::TEXTURE_CUBE_MAP,
        Texture3D => gl::TEXTURE_3D,
    }
}

fn format_to_gl(t: ::tex::TextureFormat) -> GLenum {
    match t {
        RGB8 => gl::RGB8,
        RGBA8 => gl::RGBA8,
    }
}

fn format_to_glpixel(t: ::tex::TextureFormat) -> GLenum {
    match t {
        RGB8 => gl::RGB,
        RGBA8 => gl::RGBA
    }
}

fn format_to_gltype(t: ::tex::TextureFormat) -> GLenum {
    match t {
        RGB8 | RGBA8 => gl::UNSIGNED_BYTE,
    }
}

/// Create a texture, assuming TexStorage* isn't available.
pub fn make_without_storage(info: ::tex::TextureInfo) -> Texture {
    let name = make_texture(info);

    let fmt = format_to_gl(info.format) as GLint;
    let pix = format_to_glpixel(info.format);
    let typ = format_to_gltype(info.format);

    let kind = kind_to_gl(info.kind);

    unsafe {
        match info.kind {
            Texture1D => {
                gl::TexImage1D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
            Texture1DArray => {
                gl::TexImage2D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    info.height as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
            Texture2D => {
                gl::TexImage2D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    info.height as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
            TextureCube => unimplemented!(),
            Texture2DArray | Texture3D => {
                gl::TexImage3D(
                    kind,
                    0,
                    fmt,
                    info.width as GLsizei,
                    info.height as GLsizei,
                    info.depth as GLsizei,
                    0,
                    pix,
                    typ,
                    ::std::ptr::null(),
                );
            },
        }
    }

    name
}

/// Create a texture, assuming TexStorage is available.
pub fn make_with_storage(info: ::tex::TextureInfo) -> Texture {
    use std::cmp::max;

    fn min(a: u8, b: u8) -> GLint {
        ::std::cmp::min(a, b) as GLint
    }

    fn mip_level1(w: u16) -> u8 {
        ((w as f32).log2() + 1.0) as u8
    }

    fn mip_level2(w: u16, h: u16) -> u8 {
        ((max(w, h) as f32).log2() + 1.0) as u8
    }

    fn mip_level3(w: u16, h: u16, d: u16) -> u8 {
        ((max(w, max(h, d)) as f32).log2() + 1.0) as u8
    }

    let name = make_texture(info);

    let fmt = format_to_gl(info.format);
    let kind = kind_to_gl(info.kind);

    match info.kind {
        Texture1D => {
            gl::TexStorage1D(
                kind,
                min(info.mipmap_range.val1(), mip_level1(info.width)),
                fmt,
                info.width as GLsizei
            );
        },
        Texture1DArray => {
            gl::TexStorage2D(
                kind,
                min(info.mipmap_range.val1(), mip_level1(info.width)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
            );
        },
        Texture2D => {
            gl::TexStorage2D(
                kind,
                min(info.mipmap_range.val1(), mip_level2(info.width, info.height)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
            );
        },
        TextureCube => unimplemented!(),
        Texture2DArray => {
            gl::TexStorage3D(
                kind,
                min(info.mipmap_range.val1(), mip_level2(info.width, info.height)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
                info.depth as GLsizei,
            );
        },
        Texture3D => {
            gl::TexStorage3D(
                kind,
                min(info.mipmap_range.val1(), mip_level3(info.width, info.height, info.depth)),
                fmt,
                info.width as GLsizei,
                info.height as GLsizei,
                info.depth as GLsizei,
            );
        },
    }

    name
}

/// Bind a texture + sampler to a given slot.
pub fn bind_texture(loc: GLuint, tex: Texture, sam: Sampler, info: ::tex::TextureInfo) {
    gl::ActiveTexture(gl::TEXTURE0 + loc as GLenum);
    gl::BindSampler(loc, sam);
    gl::BindTexture(kind_to_gl(info.kind), tex);
}

pub fn update_texture(tex: Texture, img: ::tex::ImageInfo, tex_info: ::tex::TextureInfo,
                      data: Box<Blob + Send>) {
    debug_assert!(img.width as u32 * img.height as u32 * img.depth as u32 == data.get_size() as u32);

    let data = data.get_address() as *const GLvoid;
    let pix = format_to_glpixel(tex_info.format);
    let typ = format_to_gltype(tex_info.format);

    gl::BindTexture(kind_to_gl(tex_info.kind), tex);

    unsafe {
        match tex_info.kind {
            Texture1D => {
                gl::TexSubImage1D(
                    kind_to_gl(tex_info.kind),
                    img.mipmap as GLint,
                    img.xoffset as GLint,
                    img.width as GLint,
                    pix,
                    typ,
                    data,
                );
            },
            Texture1DArray | Texture2D => {
                gl::TexSubImage2D(
                    kind_to_gl(tex_info.kind),
                    img.mipmap as GLint,
                    img.xoffset as GLint,
                    img.yoffset as GLint,
                    img.width as GLint,
                    img.height as GLint,
                    pix,
                    typ,
                    data,
                );
            },
            TextureCube => unimplemented!(),
            Texture2DArray | Texture3D => {
                gl::TexSubImage3D(
                    kind_to_gl(tex_info.kind),
                    img.mipmap as GLint,
                    img.xoffset as GLint,
                    img.yoffset as GLint,
                    img.zoffset as GLint,
                    img.width as GLint,
                    img.height as GLint,
                    img.depth as GLint,
                    pix,
                    typ,
                    data,
                );
            }
        }
    }
}

/// Common texture creation routine, just binds and sets mipmap ranges.
fn make_texture(info: ::tex::TextureInfo) -> Texture {
    let mut name = 0 as Texture;
    unsafe {
        gl::GenTextures(1, &mut name);
    }

    let k = kind_to_gl(info.kind);
    gl::BindTexture(k, name);

    name
}

fn wrap_to_gl(w: WrapMode) -> GLenum {
    match w {
        Tile => gl::REPEAT,
        Mirror => gl::MIRRORED_REPEAT,
        Clamp => gl::CLAMP_TO_EDGE
    }
}

pub fn make_sampler(info: ::tex::SamplerInfo) -> Sampler {
    let mut name = 0 as Sampler;
    unsafe {
        gl::GenSamplers(1, &mut name);
    }

    let (min, mag) = match info.filtering {
        Scale => (gl::NEAREST, gl::NEAREST),
        Mipmap => (gl::NEAREST_MIPMAP_NEAREST, gl::NEAREST),
        Bilinear => (gl::LINEAR_MIPMAP_NEAREST, gl::LINEAR),
        Trilinear => (gl::LINEAR_MIPMAP_LINEAR, gl::LINEAR),
        Anisotropic(fac) => {
            gl::SamplerParameterf(name, gl::TEXTURE_MAX_ANISOTROPY_EXT, fac as GLfloat);
            (gl::LINEAR_MIPMAP_LINEAR, gl::LINEAR)
        }
    };

    gl::SamplerParameteri(name, gl::TEXTURE_MIN_FILTER, min as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_MAG_FILTER, mag as GLint);

    let (s, t, r) = info.wrap_mode;
    gl::SamplerParameteri(name, gl::TEXTURE_WRAP_S, wrap_to_gl(s) as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_WRAP_T, wrap_to_gl(t) as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_WRAP_R, wrap_to_gl(r) as GLint);

    gl::SamplerParameterf(name, gl::TEXTURE_LOD_BIAS, info.lod_bias);

    let (base, max) = info.mipmap_range;
    gl::SamplerParameteri(name, gl::TEXTURE_BASE_LEVEL, base as GLint);
    gl::SamplerParameteri(name, gl::TEXTURE_MAX_LEVEL, max as GLint);

    name
}
<|endoftext|>


<commit_before>//! Contains Lea's `Number` type

// TODO allow adding i64 and f64 to numbers

use std::cmp::Ordering;
use std::hash::*;
use std::fmt;
use std::mem;
use std::ops::*;
use std::num::Wrapping;

use self::Number::*;

pub type LeaInt = i64;
pub type LeaFloat = f64;

#[derive(Copy, Clone, Debug)]
pub enum Number {
    Int(LeaInt),
    Float(LeaFloat),
}

impl fmt::Display for Number {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Int(i) => write!(fmt, "{}", i),
            Float(f) => write!(fmt, "{}", f),
        }
    }
}

/// Manual implementation needed since `Number` can be used as a table key.
impl Hash for Number {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Number::Int(i) => {
                state.write_u8(0);
                i.hash(state);
            }
            Number::Float(f) => {
                state.write_u8(1);
                state.write_i64(unsafe { mem::transmute(f) });
            }
        }
    }
}

impl<T: Into<Number> + Copy> PartialOrd<T> for Number {
    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
        match (*self, (*other).into()) {
            (Int(l), Int(r)) => l.partial_cmp(&r),
            (Int(l), Float(r)) => (l as LeaFloat).partial_cmp(&r),
            (Float(l), Int(r)) => l.partial_cmp(&(r as LeaFloat)),
            (Float(l), Float(r)) => l.partial_cmp(&r),
        }
    }
}

impl<T: Into<Number> + Copy> PartialEq<T> for Number {
    fn eq(&self, r: &T) -> bool {
        self.partial_cmp(r) == Some(Ordering::Equal)
    }
}

/// Manual implementation needed since `Number` can be used as a table key. **This isn't really
/// correct, since `NaN` still exists**.
impl Eq for Number {}

impl From<LeaFloat> for Number {
    fn from(f: LeaFloat) -> Self {
        Float(f)
    }
}

impl From<LeaInt> for Number {
    fn from(i: LeaInt) -> Self {
        Int(i)
    }
}

macro_rules! e {
    ($e:expr) => ($e);
}

macro_rules! number_impl {
    ( $tr:ident; $f:ident; ( $($wrap:tt)* ) ) => {
        impl $tr for Number {
            type Output = Self;

            fn $f(self, rhs: Self) -> Self {
                match (self, rhs) {
                    (Int(l), Int(r)) => Int(e!($($wrap)* (l).$f($($wrap)* (r))).0),
                    (Int(l), Float(r)) => Float(e!((l as LeaFloat).$f(r))),
                    (Float(l), Int(r)) => Float(e!(l.$f(r as LeaFloat))),
                    (Float(l), Float(r)) => Float(e!(l.$f(r))),
                }
            }
        }
    };
}

/// Like `number_impl`, but casts its arguments to floats before performing the operation.
macro_rules! number_impl_float {
    ( $tr:ty; $f:ident ) => {
        impl $tr for Number {
            type Output = Self;

            fn $f(self, rhs: Number) -> Number {
                match (self, rhs) {
                    (Int(l), Int(r)) => Float(e!((l as LeaFloat).$f(r as LeaFloat))),
                    (Int(l), Float(r)) => Float(e!((l as LeaFloat).$f(r))),
                    (Float(l), Int(r)) => Float(e!(l.$f(r as LeaFloat))),
                    (Float(l), Float(r)) => Float(e!(l.$f(r))),
                }
            }
        }
    };
}

/// Like `number_impl`, but always casts its arguments to ints
macro_rules! number_impl_int {
    ( $tr:ty; $f:ident; $tf:ident; ( $($wrap:tt)* ) ) => {
        impl $tr for Number {
            type Output = Self;

            fn $f(self, rhs: Self) -> Self {
                match (self, rhs) {
                    (Int(l), Int(r)) => Int(e!($($wrap)* (l).$tf($($wrap)* (r))).0),
                    (Int(l), Float(r)) => Int(e!(l.$tf(r as LeaInt))),
                    (Float(l), Int(r)) => Int(e!((l as LeaInt).$tf(r))),
                    (Float(l), Float(r)) => Int(e!((l as LeaInt).$tf(r as LeaInt))),
                }
            }
        }
    };
}

macro_rules! number_impl_shift {
    ( $tr:ident; $f:ident; $identity:ident; $reverse:ident ) => {
        impl $tr<Number> for Number {
            type Output = Number;

            fn $f(self, rhs: Number) -> Number {
                match (self, rhs) {
                    (Int(l), Int(r)) if r < 0 => Int(l.$reverse((-r) as u32)),
                    (Int(l), Int(r)) => Int(l.$identity(r as u32)),
                    (Int(l), Float(r)) if r < 0.0 => Int(l.$reverse((-r) as u32)),
                    (Int(l), Float(r)) => Int(l.$identity(r as u32)),
                    (Float(l), Int(r)) if r < 0 => Int((l as LeaInt).$reverse((-r) as u32)),
                    (Float(l), Int(r)) => Int((l as LeaInt).$identity(r as u32)),
                    (Float(l), Float(r)) if r < 0.0 => Int((l as LeaInt).$reverse((-r) as u32)),
                    (Float(l), Float(r)) => Int((l as LeaInt).$identity(r as u32)),
                }
            }
        }
    };
}

number_impl!(Add; add; (Wrapping));
number_impl!(Sub; sub; (Wrapping));
number_impl!(Mul; mul; (Wrapping));
number_impl_float!(Div; div);
number_impl_float!(Rem; rem);
number_impl_int!(BitAnd; bitand; bitand; (Wrapping));
number_impl_int!(BitOr; bitor; bitor; (Wrapping));
number_impl_int!(BitXor; bitxor; bitxor; (Wrapping));
number_impl_shift!(Shl; shl; wrapping_shl; wrapping_shr);
number_impl_shift!(Shr; shr; wrapping_shr; wrapping_shl);

impl Neg for Number {
    type Output = Self;

    fn neg(self) -> Self {
        match self {
            Int(i) => Int(i.wrapping_neg()),
            Float(f) => Float(-f),
        }
    }
}

impl Not for Number {
    type Output = Self;

    fn not(self) -> Self {
        match self {
            Int(i) => Int(!i),
            Float(f) => Int(!(f as LeaInt)),
        }
    }
}

impl Number {
    /// Exponentiate two numbers
    pub fn pow<T: Into<Self> + Copy>(self, exp: T) -> Self {
        // FIXME Overflow semantics unclear: Rust has no `wrapping_pow`
        match (self, exp.into()) {
            (Int(b), Int(e)) => Int(b.pow(e as u32)),
            (Int(b), Float(e)) => Float((b as LeaFloat).powf(e)),
            (Float(b), Int(e)) => Float(b.powi(e as i32)),
            (Float(b), Float(e)) => Float(b.powf(e)),
        }
    }
}

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

    #[test]
    fn test() {
        let l = Int(5);
        let r = Float(6.5);
        assert_eq!(l, 5);
        assert_eq!(l, 5.0);
        assert_eq!(r, 6.5);
        assert_eq!(l + r, 11.5);
        assert!(l < r);
        assert!(r > l);
        assert!(l < 10);
        assert!(l < 10.1);
        assert!(r < 7);
        assert!(r > 6);
    }
}
<commit_msg>Make number impls generic<commit_after>//! Contains Lea's `Number` type

use std::cmp::Ordering;
use std::hash::*;
use std::fmt;
use std::mem;
use std::ops::*;
use std::num::Wrapping;

use self::Number::*;

pub type LeaInt = i64;
pub type LeaFloat = f64;

#[derive(Copy, Clone, Debug)]
pub enum Number {
    Int(LeaInt),
    Float(LeaFloat),
}

impl fmt::Display for Number {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Int(i) => write!(fmt, "{}", i),
            Float(f) => write!(fmt, "{}", f),
        }
    }
}

/// Manual implementation needed since `Number` can be used as a table key.
impl Hash for Number {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match *self {
            Number::Int(i) => {
                state.write_u8(0);
                i.hash(state);
            }
            Number::Float(f) => {
                state.write_u8(1);
                state.write_i64(unsafe { mem::transmute(f) });
            }
        }
    }
}

impl<T: Into<Number> + Copy> PartialOrd<T> for Number {
    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
        match (*self, (*other).into()) {
            (Int(l), Int(r)) => l.partial_cmp(&r),
            (Int(l), Float(r)) => (l as LeaFloat).partial_cmp(&r),
            (Float(l), Int(r)) => l.partial_cmp(&(r as LeaFloat)),
            (Float(l), Float(r)) => l.partial_cmp(&r),
        }
    }
}

impl<T: Into<Number> + Copy> PartialEq<T> for Number {
    fn eq(&self, r: &T) -> bool {
        self.partial_cmp(r) == Some(Ordering::Equal)
    }
}

/// Manual implementation needed since `Number` can be used as a table key. **This isn't really
/// correct, since `NaN` still exists**.
impl Eq for Number {}

impl From<LeaFloat> for Number {
    fn from(f: LeaFloat) -> Self {
        Float(f)
    }
}

impl From<LeaInt> for Number {
    fn from(i: LeaInt) -> Self {
        Int(i)
    }
}

macro_rules! e {
    ($e:expr) => ($e);
}

macro_rules! number_impl {
    ( $tr:ident; $f:ident; ( $($wrap:tt)* ) ) => {
        impl<T: Into<Number>> $tr<T> for Number {
            type Output = Self;

            fn $f(self, rhs: T) -> Self {
                match (self, rhs.into()) {
                    (Int(l), Int(r)) => Int(e!($($wrap)* (l).$f($($wrap)* (r))).0),
                    (Int(l), Float(r)) => Float(e!((l as LeaFloat).$f(r))),
                    (Float(l), Int(r)) => Float(e!(l.$f(r as LeaFloat))),
                    (Float(l), Float(r)) => Float(e!(l.$f(r))),
                }
            }
        }
    };
}

/// Like `number_impl`, but casts its arguments to floats before performing the operation.
macro_rules! number_impl_float {
    ( $tr:ident; $f:ident ) => {
        impl<T: Into<Number>> $tr<T> for Number {
            type Output = Self;

            fn $f(self, rhs: T) -> Self {
                match (self, rhs.into()) {
                    (Int(l), Int(r)) => Float(e!((l as LeaFloat).$f(r as LeaFloat))),
                    (Int(l), Float(r)) => Float(e!((l as LeaFloat).$f(r))),
                    (Float(l), Int(r)) => Float(e!(l.$f(r as LeaFloat))),
                    (Float(l), Float(r)) => Float(e!(l.$f(r))),
                }
            }
        }
    };
}

/// Like `number_impl`, but always casts its arguments to ints
macro_rules! number_impl_int {
    ( $tr:ident; $f:ident; $tf:ident; ( $($wrap:tt)* ) ) => {
        impl<T: Into<Number>> $tr<T> for Number {
            type Output = Self;

            fn $f(self, rhs: T) -> Self {
                match (self, rhs.into()) {
                    (Int(l), Int(r)) => Int(e!($($wrap)* (l).$tf($($wrap)* (r))).0),
                    (Int(l), Float(r)) => Int(e!(l.$tf(r as LeaInt))),
                    (Float(l), Int(r)) => Int(e!((l as LeaInt).$tf(r))),
                    (Float(l), Float(r)) => Int(e!((l as LeaInt).$tf(r as LeaInt))),
                }
            }
        }
    };
}

macro_rules! number_impl_shift {
    ( $tr:ident; $f:ident; $identity:ident; $reverse:ident ) => {
        impl $tr<Number> for Number {
            type Output = Number;

            fn $f(self, rhs: Number) -> Number {
                match (self, rhs) {
                    (Int(l), Int(r)) if r < 0 => Int(l.$reverse((-r) as u32)),
                    (Int(l), Int(r)) => Int(l.$identity(r as u32)),
                    (Int(l), Float(r)) if r < 0.0 => Int(l.$reverse((-r) as u32)),
                    (Int(l), Float(r)) => Int(l.$identity(r as u32)),
                    (Float(l), Int(r)) if r < 0 => Int((l as LeaInt).$reverse((-r) as u32)),
                    (Float(l), Int(r)) => Int((l as LeaInt).$identity(r as u32)),
                    (Float(l), Float(r)) if r < 0.0 => Int((l as LeaInt).$reverse((-r) as u32)),
                    (Float(l), Float(r)) => Int((l as LeaInt).$identity(r as u32)),
                }
            }
        }
    };
}

number_impl!(Add; add; (Wrapping));
number_impl!(Sub; sub; (Wrapping));
number_impl!(Mul; mul; (Wrapping));
number_impl_float!(Div; div);
number_impl_float!(Rem; rem);
number_impl_int!(BitAnd; bitand; bitand; (Wrapping));
number_impl_int!(BitOr; bitor; bitor; (Wrapping));
number_impl_int!(BitXor; bitxor; bitxor; (Wrapping));
number_impl_shift!(Shl; shl; wrapping_shl; wrapping_shr);
number_impl_shift!(Shr; shr; wrapping_shr; wrapping_shl);

impl Neg for Number {
    type Output = Self;

    fn neg(self) -> Self {
        match self {
            Int(i) => Int(i.wrapping_neg()),
            Float(f) => Float(-f),
        }
    }
}

impl Not for Number {
    type Output = Self;

    fn not(self) -> Self {
        match self {
            Int(i) => Int(!i),
            Float(f) => Int(!(f as LeaInt)),
        }
    }
}

impl Number {
    /// Exponentiate two numbers
    pub fn pow<T: Into<Self> + Copy>(self, exp: T) -> Self {
        // FIXME Overflow semantics unclear: Rust has no `wrapping_pow`
        match (self, exp.into()) {
            (Int(b), Int(e)) => Int(b.pow(e as u32)),
            (Int(b), Float(e)) => Float((b as LeaFloat).powf(e)),
            (Float(b), Int(e)) => Float(b.powi(e as i32)),
            (Float(b), Float(e)) => Float(b.powf(e)),
        }
    }
}

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

    #[test]
    fn test() {
        let l = Int(5);
        let r = Float(6.5);
        assert_eq!(l, 5);
        assert_eq!(l, 5.0);
        assert_eq!(r, 6.5);
        assert_eq!(l + r, 11.5);
        assert!(l < r);
        assert!(r > l);
        assert!(l < 10);
        assert!(l < 10.1);
        assert!(r < 7);
        assert!(r > 6);
        assert_eq!(l + 4, 9);
        assert_eq!(l - 6, -1);
        assert_eq!(l / 1, l);
        assert_eq!(l & 1, 1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Higher level communication abstractions.

*/

#[allow(missing_doc)];

/// An extension of `pipes::stream` that allows both sending and receiving.
pub struct DuplexStream<T, U> {
    priv chan: Chan<T>,
    priv port: Port<U>,
}

// Allow these methods to be used without import:
impl<T:Send,U:Send> DuplexStream<T, U> {
    /// Creates a bidirectional stream.
    pub fn new() -> (DuplexStream<T, U>, DuplexStream<U, T>) {
        let (p1, c2) = Chan::new();
        let (p2, c1) = Chan::new();
        (DuplexStream { chan: c1, port: p1 },
         DuplexStream { chan: c2, port: p2 })
    }
    pub fn send(&self, x: T) {
        self.chan.send(x)
    }
    pub fn try_send(&self, x: T) -> bool {
        self.chan.try_send(x)
    }
    pub fn recv(&self) -> U {
        self.port.recv()
    }
    pub fn try_recv(&self) -> Option<U> {
        self.port.try_recv()
    }
    pub fn recv_opt(&self) -> Option<U> {
        self.port.recv_opt()
    }
}

/// An extension of `pipes::stream` that provides synchronous message sending.
pub struct SyncChan<T> { priv duplex_stream: DuplexStream<T, ()> }
/// An extension of `pipes::stream` that acknowledges each message received.
pub struct SyncPort<T> { priv duplex_stream: DuplexStream<(), T> }

impl<T: Send> SyncChan<T> {
    pub fn send(&self, val: T) {
        assert!(self.try_send(val), "SyncChan.send: receiving port closed");
    }

    /// Sends a message, or report if the receiver has closed the connection
    /// before receiving.
    pub fn try_send(&self, val: T) -> bool {
        self.duplex_stream.try_send(val) && self.duplex_stream.recv_opt().is_some()
    }
}

impl<T: Send> SyncPort<T> {
    pub fn recv(&self) -> T {
        self.recv_opt().expect("SyncPort.recv: sending channel closed")
    }

    pub fn recv_opt(&self) -> Option<T> {
        self.duplex_stream.recv_opt().map(|val| {
            self.duplex_stream.try_send(());
            val
        })
    }

    pub fn try_recv(&self) -> Option<T> {
        self.duplex_stream.try_recv().map(|val| {
            self.duplex_stream.try_send(());
            val
        })
    }
}

/// Creates a stream whose channel, upon sending a message, blocks until the
/// message is received.
pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
    let (chan_stream, port_stream) = DuplexStream::new();
    (SyncPort { duplex_stream: port_stream },
     SyncChan { duplex_stream: chan_stream })
}

#[cfg(test)]
mod test {
    use comm::{DuplexStream, rendezvous};
    use std::rt::test::run_in_uv_task;

    #[test]
    pub fn DuplexStream1() {
        let (mut left, mut right) = DuplexStream::new();

        left.send(~"abc");
        right.send(123);

        assert!(left.recv() == 123);
        assert!(right.recv() == ~"abc");
    }

    #[test]
    pub fn basic_rendezvous_test() {
        let (mut port, chan) = rendezvous();

        do spawn {
            let mut chan = chan;
            chan.send("abc");
        }

        assert!(port.recv() == "abc");
    }

    #[test]
    fn recv_a_lot() {
        // Rendezvous streams should be able to handle any number of messages being sent
        do run_in_uv_task {
            let (mut port, chan) = rendezvous();
            do spawn {
                let mut chan = chan;
                1000000.times(|| { chan.send(()) })
            }
            1000000.times(|| { port.recv() })
        }
    }

    #[test]
    fn send_and_fail_and_try_recv() {
        let (mut port, chan) = rendezvous();
        do spawn {
            let mut chan = chan;
            chan.duplex_stream.send(()); // Can't access this field outside this module
            fail!()
        }
        port.recv()
    }

    #[test]
    fn try_send_and_recv_then_fail_before_ack() {
        let (port, mut chan) = rendezvous();
        do spawn {
            let mut port = port;
            port.duplex_stream.recv();
            fail!()
        }
        chan.try_send(());
    }

    #[test]
    #[should_fail]
    fn send_and_recv_then_fail_before_ack() {
        let (port, mut chan) = rendezvous();
        do spawn {
            let mut port = port;
            port.duplex_stream.recv();
            fail!()
        }
        chan.send(());
    }
}
<commit_msg>extra: silence warnings during testing.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Higher level communication abstractions.

*/

#[allow(missing_doc)];

/// An extension of `pipes::stream` that allows both sending and receiving.
pub struct DuplexStream<T, U> {
    priv chan: Chan<T>,
    priv port: Port<U>,
}

// Allow these methods to be used without import:
impl<T:Send,U:Send> DuplexStream<T, U> {
    /// Creates a bidirectional stream.
    pub fn new() -> (DuplexStream<T, U>, DuplexStream<U, T>) {
        let (p1, c2) = Chan::new();
        let (p2, c1) = Chan::new();
        (DuplexStream { chan: c1, port: p1 },
         DuplexStream { chan: c2, port: p2 })
    }
    pub fn send(&self, x: T) {
        self.chan.send(x)
    }
    pub fn try_send(&self, x: T) -> bool {
        self.chan.try_send(x)
    }
    pub fn recv(&self) -> U {
        self.port.recv()
    }
    pub fn try_recv(&self) -> Option<U> {
        self.port.try_recv()
    }
    pub fn recv_opt(&self) -> Option<U> {
        self.port.recv_opt()
    }
}

/// An extension of `pipes::stream` that provides synchronous message sending.
pub struct SyncChan<T> { priv duplex_stream: DuplexStream<T, ()> }
/// An extension of `pipes::stream` that acknowledges each message received.
pub struct SyncPort<T> { priv duplex_stream: DuplexStream<(), T> }

impl<T: Send> SyncChan<T> {
    pub fn send(&self, val: T) {
        assert!(self.try_send(val), "SyncChan.send: receiving port closed");
    }

    /// Sends a message, or report if the receiver has closed the connection
    /// before receiving.
    pub fn try_send(&self, val: T) -> bool {
        self.duplex_stream.try_send(val) && self.duplex_stream.recv_opt().is_some()
    }
}

impl<T: Send> SyncPort<T> {
    pub fn recv(&self) -> T {
        self.recv_opt().expect("SyncPort.recv: sending channel closed")
    }

    pub fn recv_opt(&self) -> Option<T> {
        self.duplex_stream.recv_opt().map(|val| {
            self.duplex_stream.try_send(());
            val
        })
    }

    pub fn try_recv(&self) -> Option<T> {
        self.duplex_stream.try_recv().map(|val| {
            self.duplex_stream.try_send(());
            val
        })
    }
}

/// Creates a stream whose channel, upon sending a message, blocks until the
/// message is received.
pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
    let (chan_stream, port_stream) = DuplexStream::new();
    (SyncPort { duplex_stream: port_stream },
     SyncChan { duplex_stream: chan_stream })
}

#[cfg(test)]
mod test {
    use comm::{DuplexStream, rendezvous};
    use std::rt::test::run_in_uv_task;

    #[test]
    pub fn DuplexStream1() {
        let (left, right) = DuplexStream::new();

        left.send(~"abc");
        right.send(123);

        assert!(left.recv() == 123);
        assert!(right.recv() == ~"abc");
    }

    #[test]
    pub fn basic_rendezvous_test() {
        let (port, chan) = rendezvous();

        do spawn {
            chan.send("abc");
        }

        assert!(port.recv() == "abc");
    }

    #[test]
    fn recv_a_lot() {
        // Rendezvous streams should be able to handle any number of messages being sent
        do run_in_uv_task {
            let (port, chan) = rendezvous();
            do spawn {
                1000000.times(|| { chan.send(()) })
            }
            1000000.times(|| { port.recv() })
        }
    }

    #[test]
    fn send_and_fail_and_try_recv() {
        let (port, chan) = rendezvous();
        do spawn {
            chan.duplex_stream.send(()); // Can't access this field outside this module
            fail!()
        }
        port.recv()
    }

    #[test]
    fn try_send_and_recv_then_fail_before_ack() {
        let (port, chan) = rendezvous();
        do spawn {
            port.duplex_stream.recv();
            fail!()
        }
        chan.try_send(());
    }

    #[test]
    #[should_fail]
    fn send_and_recv_then_fail_before_ack() {
        let (port, chan) = rendezvous();
        do spawn {
            port.duplex_stream.recv();
            fail!()
        }
        chan.send(());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Habitat helps you build, manage, and run applications - on bare metal, in the cloud, and in
//! containers. You can [read more about it on the website](https://www.habitat.sh/).
//!
//! Habitat contains two main components:
//!
//! * `hab-plan-build`, takes a plan ('plan.sh'), a description of how to build a piece of software,
//! written in [bash](http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html), which produces an atomic
//! package.
//! * `hab-sup`, a run-time executable that knows how to download, install, serve, and
//! manage services defined in packages.
//!
//! # hab-plan-build
//!
//! The documentation for hab-plan-build is generated automatically from the script itself, [and
//! can be found here](hab-plan-build/hab-plan-build.html). You can find it in the source tree at
//! `components/plan-build`.
//!
//! # The Supervisor
//!
//! The Supervisor is primarily utilized through the `hab-sup` command; it can also be used from
//! within Rust as a library. This documentation covers both uses; it explains how things are used
//! from the command line in close proximity to the documentation of the library itself. A few
//! useful starting points:
//!
//! * [The Habitat Command Line Reference](command)
//! * [The Habitat Supervisor Sidecar; http interface to promises](sidecar)

extern crate actix;
extern crate actix_web;
extern crate ansi_term;
#[macro_use]
extern crate bitflags;
extern crate byteorder;
#[cfg(target_os = "linux")]
extern crate caps;
#[macro_use]
extern crate clap;
extern crate crypto;
#[cfg(windows)]
extern crate ctrlc;
#[macro_use]
extern crate features;
#[macro_use]
extern crate futures;
extern crate glob;
extern crate hab;
extern crate habitat_butterfly as butterfly;
extern crate habitat_common as common;
#[macro_use]
extern crate habitat_core as hcore;
extern crate habitat_api_client as api_client;
extern crate habitat_eventsrv_client as eventsrv_client;
extern crate habitat_launcher_client as launcher_client;
extern crate habitat_sup_protocol as protocol;
extern crate handlebars;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
extern crate notify;
extern crate prost;
extern crate protobuf;
extern crate rand;
extern crate regex;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[allow(unused_imports)]
#[macro_use]
extern crate serde_json;
extern crate serde_transcode;
extern crate serde_yaml;
extern crate tempfile;
extern crate time;
extern crate tokio;
extern crate tokio_codec;
#[macro_use]
extern crate tokio_core;
extern crate toml;
extern crate url;
extern crate valico;

#[cfg(test)]
extern crate json;

#[macro_export]
/// Creates a new SupError, embedding the current file name, line number, column, and module path.
macro_rules! sup_error {
    ($p:expr) => {{
        use $crate::error::SupError;
        SupError::new($p, LOGKEY, file!(), line!(), column!())
    }};
}

#[cfg(test)]
#[macro_use]
pub mod cli_test_helpers;
pub mod census;
pub mod cli;
pub mod command;
pub mod config;
pub mod ctl_gateway;
pub mod error;
pub mod fs;
pub mod http_gateway;
pub mod manager;
mod sys;
pub mod templating;
#[cfg(test)]
pub mod test_helpers;
pub mod util;

use std::env;
use std::path::PathBuf;

lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = env::args().next().map(|p| PathBuf::from(p));
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// List enables printing out the list features which can be dynamically enabled
/// TestExit enables triggering an abrupt exit to simulate failures
/// TestBootFail exits with a fatal error before even calling boot()
/// Search for feat::is_enabled(feat::FeatureName) to learn more
features! {
    pub mod feat {
        const List          = 0b00000001,
        const TestExit      = 0b00000010,
        const TestBootFail  = 0b00000100,
        const RedactHTTP    = 0b00001000,
        const IgnoreSignals = 0b00010000
    }
}

pub const PRODUCT: &'static str = "hab-sup";
pub const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/VERSION"));

#[derive(Copy, Clone)]
pub enum ShutdownReason {
    Departed,
    LauncherStopping,
    PkgUpdating,
    Signal,
    SvcStopCmd,
}
<commit_msg>removing unused macro_use<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Habitat helps you build, manage, and run applications - on bare metal, in the cloud, and in
//! containers. You can [read more about it on the website](https://www.habitat.sh/).
//!
//! Habitat contains two main components:
//!
//! * `hab-plan-build`, takes a plan ('plan.sh'), a description of how to build a piece of software,
//! written in [bash](http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html), which produces an atomic
//! package.
//! * `hab-sup`, a run-time executable that knows how to download, install, serve, and
//! manage services defined in packages.
//!
//! # hab-plan-build
//!
//! The documentation for hab-plan-build is generated automatically from the script itself, [and
//! can be found here](hab-plan-build/hab-plan-build.html). You can find it in the source tree at
//! `components/plan-build`.
//!
//! # The Supervisor
//!
//! The Supervisor is primarily utilized through the `hab-sup` command; it can also be used from
//! within Rust as a library. This documentation covers both uses; it explains how things are used
//! from the command line in close proximity to the documentation of the library itself. A few
//! useful starting points:
//!
//! * [The Habitat Command Line Reference](command)
//! * [The Habitat Supervisor Sidecar; http interface to promises](sidecar)

extern crate actix;
extern crate actix_web;
extern crate ansi_term;
#[macro_use]
extern crate bitflags;
extern crate byteorder;
#[cfg(target_os = "linux")]
extern crate caps;
extern crate clap;
extern crate crypto;
#[cfg(windows)]
extern crate ctrlc;
#[macro_use]
extern crate features;
#[macro_use]
extern crate futures;
extern crate glob;
extern crate hab;
extern crate habitat_butterfly as butterfly;
extern crate habitat_common as common;
#[macro_use]
extern crate habitat_core as hcore;
extern crate habitat_api_client as api_client;
extern crate habitat_eventsrv_client as eventsrv_client;
extern crate habitat_launcher_client as launcher_client;
extern crate habitat_sup_protocol as protocol;
extern crate handlebars;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
extern crate notify;
extern crate prost;
extern crate protobuf;
extern crate rand;
extern crate regex;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[allow(unused_imports)]
#[macro_use]
extern crate serde_json;
extern crate serde_transcode;
extern crate serde_yaml;
extern crate tempfile;
extern crate time;
extern crate tokio;
extern crate tokio_codec;
#[macro_use]
extern crate tokio_core;
extern crate toml;
extern crate url;
extern crate valico;

#[cfg(test)]
extern crate json;

#[macro_export]
/// Creates a new SupError, embedding the current file name, line number, column, and module path.
macro_rules! sup_error {
    ($p:expr) => {{
        use $crate::error::SupError;
        SupError::new($p, LOGKEY, file!(), line!(), column!())
    }};
}

#[cfg(test)]
#[macro_use]
pub mod cli_test_helpers;
pub mod census;
pub mod cli;
pub mod command;
pub mod config;
pub mod ctl_gateway;
pub mod error;
pub mod fs;
pub mod http_gateway;
pub mod manager;
mod sys;
pub mod templating;
#[cfg(test)]
pub mod test_helpers;
pub mod util;

use std::env;
use std::path::PathBuf;

lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        let arg0 = env::args().next().map(|p| PathBuf::from(p));
        arg0.as_ref()
            .and_then(|p| p.file_stem())
            .and_then(|p| p.to_str())
            .unwrap()
            .to_string()
    };
}

/// List enables printing out the list features which can be dynamically enabled
/// TestExit enables triggering an abrupt exit to simulate failures
/// TestBootFail exits with a fatal error before even calling boot()
/// Search for feat::is_enabled(feat::FeatureName) to learn more
features! {
    pub mod feat {
        const List          = 0b00000001,
        const TestExit      = 0b00000010,
        const TestBootFail  = 0b00000100,
        const RedactHTTP    = 0b00001000,
        const IgnoreSignals = 0b00010000
    }
}

pub const PRODUCT: &'static str = "hab-sup";
pub const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/VERSION"));

#[derive(Copy, Clone)]
pub enum ShutdownReason {
    Departed,
    LauncherStopping,
    PkgUpdating,
    Signal,
    SvcStopCmd,
}
<|endoftext|>


<commit_before>use super::memory::MemSegment;
use audio::{AudioOut};

pub type Sample = i16;

const CPU_CYCLES_PER_EVEN_TICK: u64 = 7438;
const CPUCYCLES_PER_ODD_TICK: u64 = 7439;

const NES_FPS: usize = 60;
const FRAMES_PER_BUFFER : usize = 6;
pub const BUFFERS_PER_SECOND : usize = NES_FPS / FRAMES_PER_BUFFER; //must always be a positive integer

const SAMPLE_RATE: usize = 44100;
const SAMPLES_PER_FRAME: usize = (SAMPLE_RATE / NES_FPS);
pub const BUFFER_SIZE: usize = SAMPLES_PER_FRAME * FRAMES_PER_BUFFER;

pub struct OutputBuffer {
    pub samples: [i16; BUFFER_SIZE as usize],
}

bitflags! {
    flags Frame : u8 {
        const MODE = 0b1000_0000, //0 = 4-step, 1 = 5-step
        const IRQ  = 0b0100_0000, //0 = disabled, 1 = enabled
    }
}

struct Pulse {
    flags: u8,
    sweep: u8,
    timer: u8,
    length: u8,
}

impl Pulse {
    fn new() -> Pulse {
        Pulse {
            flags: 0,
            sweep: 0,
            timer: 0,
            length: 0,
        }
    }
}

struct Triangle {
    counter: u8,
    timer: u8,
    length: u8,
}

impl Triangle {
    fn new() -> Triangle {
        Triangle {
            counter: 0,
            timer: 0,
            length: 0,
        }
    }
}

struct Noise {
    volume: u8,
    mode: u8,
    length: u8,
}

impl Noise {
    fn new() -> Noise {
        Noise {
            volume: 0,
            mode: 0,
            length: 0,
        }
    }
}

struct DMC {
    freq: u8,
    direct: u8,
    addr: u8,
    length: u8,
}

impl DMC {
    fn new() -> DMC {
        DMC {
            freq: 0,
            direct: 0,
            addr: 0,
            length: 0,
        }
    }
}

pub struct APU {
    pulse1: Pulse,
    pulse2: Pulse,
    triangle: Triangle,
    noise: Noise,
    dmc: DMC,
    frame: Frame,
    control: u8,
    status: u8,

    device: Box<AudioOut>,

    global_cyc: u64,
    tick: u64,
    next_tick_cyc: u64,
}

impl APU {
    pub fn new( device: Box<AudioOut> ) -> APU {
        APU {
            pulse1: Pulse::new(),
            pulse2: Pulse::new(),
            triangle: Triangle::new(),
            noise: Noise::new(),
            dmc: DMC::new(),
            frame: Frame::empty(),
            control: 0,
            status: 0,

            device: device,

            global_cyc: 0,
            tick: 0,
            next_tick_cyc: 0,
        }
    }

    pub fn run_to(&mut self, cpu_cycle: u64) {
        while ( self.global_cyc < cpu_cycle ) {
            if self.global_cyc == self.next_tick_cyc {
                self.tick();
                self.tick += 1;
                self.next_tick_cyc += if self.tick %2 == 0 {
                    CPU_CYCLES_PER_EVEN_TICK
                }
                else {
                    CPUCYCLES_PER_ODD_TICK
                }
            }
            self.global_cyc += 1;
        }
    }

    ///Represents the 240Hz output of the frame sequencer's divider
    fn tick(&mut self) {
        if !self.frame.contains(MODE) {
            match self.tick % 4 {
                0 => { self.envelope_tick(); }
                1 => { self.envelope_tick(); self.length_tick(); }
                2 => { self.envelope_tick(); }
                3 => { self.envelope_tick(); self.length_tick(); self.raise_irq(); }
                _ => ()
            }
        }
        else {
            match self.tick % 5 {
                0 => { self.envelope_tick(); self.length_tick() }
                1 => { self.envelope_tick(); }
                2 => { self.envelope_tick(); self.length_tick() }
                3 => { self.envelope_tick(); }
                4 => ()
                _ => ()
            }
        }
    }

    fn envelope_tick(&mut self) {

    }

    fn length_tick(&mut self) {

    }

    fn raise_irq(&mut self) {

    }

    pub fn play(&mut self) {

    }
}

impl MemSegment for APU {
    fn read(&mut self, idx: u16) -> u8 {
        match idx % 0x20 {
            0x0015 => self.status,
            _ => 0,
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx % 0x20 {
            0x0000 => self.pulse1.flags = val,
            0x0001 => self.pulse1.sweep = val,
            0x0002 => self.pulse1.timer = val,
            0x0003 => self.pulse1.length = val,
            0x0004 => self.pulse2.flags = val,
            0x0005 => self.pulse2.sweep = val,
            0x0006 => self.pulse2.timer = val,
            0x0007 => self.pulse2.length = val,
            0x0008 => self.triangle.counter = val,
            0x0009 => (),
            0x000A => self.triangle.timer = val,
            0x000B => self.triangle.length = val,
            0x000C => self.noise.volume = val,
            0x000D => (),
            0x000E => self.noise.mode = val,
            0x000F => self.noise.length = val,
            0x0010 => self.dmc.freq = val,
            0x0011 => self.dmc.direct = val,
            0x0012 => self.dmc.addr = val,
            0x0013 => self.dmc.length = val,
            0x0014 => (),
            0x0015 => self.control = val,
            0x0016 => (),
            0x0017 => {
                self.frame = Frame::from_bits_truncate(val);
                self.tick = 0;
                self.next_tick_cyc = if self.frame.contains( MODE ) {
                    self.global_cyc;
                }
                else {
                    self.global_cyc + CPU_CYCLES_PER_EVEN_TICK;
                }
            },
            _ => (),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory::MemSegment;
    use audio::DummyAudioOut;

    fn assert_register_writable(idx: u16, getter: &Fn(&APU) -> u8) {
        let mut apu = APU::new(Box::new(DummyAudioOut));
        apu.write(idx, 12);
        assert_eq!(getter(&apu), 12);
        apu.write(idx, 125);
        assert_eq!(getter(&apu), 125);
    }

    fn assert_register_not_readable(idx: u16) {
        let mut apu = APU::new(Box::new(DummyAudioOut));
        apu.write(idx, 12);
        assert_eq!(apu.read(idx), 0);
        apu.write(idx, 125);
        assert_eq!(apu.read(idx), 0);
    }

    fn test_writable_register(idx: u16, getter: &Fn(&APU) -> u8) {
        assert_register_writable(idx, getter);
        assert_register_not_readable(idx);
    }

    #[test]
    fn test_writable_registers() {
        test_writable_register(0x4000, &|ref apu| apu.pulse1.flags);
        test_writable_register(0x4001, &|ref apu| apu.pulse1.sweep);
        test_writable_register(0x4002, &|ref apu| apu.pulse1.timer);
        test_writable_register(0x4003, &|ref apu| apu.pulse1.length);
        test_writable_register(0x4004, &|ref apu| apu.pulse2.flags);
        test_writable_register(0x4005, &|ref apu| apu.pulse2.sweep);
        test_writable_register(0x4006, &|ref apu| apu.pulse2.timer);
        test_writable_register(0x4007, &|ref apu| apu.pulse2.length);
        test_writable_register(0x4008, &|ref apu| apu.triangle.counter);
        test_writable_register(0x400A, &|ref apu| apu.triangle.timer);
        test_writable_register(0x400B, &|ref apu| apu.triangle.length);
        test_writable_register(0x400C, &|ref apu| apu.noise.volume);
        test_writable_register(0x400E, &|ref apu| apu.noise.mode);
        test_writable_register(0x400F, &|ref apu| apu.noise.length);
        test_writable_register(0x4010, &|ref apu| apu.dmc.freq);
        test_writable_register(0x4011, &|ref apu| apu.dmc.direct);
        test_writable_register(0x4012, &|ref apu| apu.dmc.addr);
        test_writable_register(0x4013, &|ref apu| apu.dmc.length);
        test_writable_register(0x4017, &|ref apu| apu.frame);
    }
}
<commit_msg>Implemented APU length counter.<commit_after>use super::memory::MemSegment;
use audio::{AudioOut};

pub type Sample = i16;

const CPU_CYCLES_PER_EVEN_TICK: u64 = 7438;
const CPUCYCLES_PER_ODD_TICK: u64 = 7439;

const NES_FPS: usize = 60;
const FRAMES_PER_BUFFER : usize = 6;
pub const BUFFERS_PER_SECOND : usize = NES_FPS / FRAMES_PER_BUFFER; //must always be a positive integer

const SAMPLE_RATE: usize = 44100;
const SAMPLES_PER_FRAME: usize = (SAMPLE_RATE / NES_FPS);
pub const BUFFER_SIZE: usize = SAMPLES_PER_FRAME * FRAMES_PER_BUFFER;

static LENGTH_TABLE: [u8; 32] = [
    0x0A, 0xFE,
    0x14, 0x02,
    0x28, 0x04,
    0x50, 0x06,
    0xA0, 0x08,
    0x3C, 0x0A,
    0x0E, 0x0C,
    0x1A, 0x0E,
    0x0C, 0x10,
    0x18, 0x12,
    0x30, 0x14,
    0x60, 0x16,
    0xC0, 0x18,
    0x48, 0x1A,
    0x10, 0x1C,
    0x20, 0x1E,
];

pub struct OutputBuffer {
    pub samples: [i16; BUFFER_SIZE as usize],
}

bitflags! {
    flags Frame : u8 {
        const MODE = 0b1000_0000, //0 = 4-step, 1 = 5-step
        const IRQ  = 0b0100_0000, //0 = disabled, 1 = enabled
    }
}

trait Writable {
    fn write(&mut self, idx: u16, val: u8);
}

struct Length {
    halt_bit: usize,
    halted: bool,
    remaining: u8,
}

impl Length {
    fn write_halt(&mut self, val: u8) {
        self.halted = (val >> self.halt_bit ) & 0x01 != 0;
        if self.halted {
            self.remaining = 0;
        }
    }

    fn write_counter(&mut self, val: u8) {
        if !self.halted {
            self.remaining = LENGTH_TABLE[(val >> 3) as usize];
        }
    }

    fn is_enabled(&self) -> bool {
        self.remaining > 0
    }

    fn tick(&mut self) {
        self.remaining = self.remaining.saturating_sub(1);
    }

    fn new(halt_bit: usize) -> Length {
        Length {
            halt_bit: halt_bit,
            halted: false,
            remaining: 0,
        }
    }
}

struct Pulse {
    flags: u8,
    sweep: u8,
    timer: u8,
    length: Length,
}

impl Pulse {
    fn new() -> Pulse {
        Pulse {
            flags: 0,
            sweep: 0,
            timer: 0,
            length: Length::new(5),
        }
    }
}

impl Writable for Pulse {
    fn write(&mut self, idx: u16, val: u8) {
        match idx % 4 {
            0 => self.length.write_halt(val),
            1 => (),
            2 => (),
            3 => self.length.write_counter(val),
            _ => (),
        }
    }
}

struct Triangle {
    counter: u8,
    timer: u8,
    length: Length,
}

impl Triangle {
    fn new() -> Triangle {
        Triangle {
            counter: 0,
            timer: 0,
            length: Length::new(7),
        }
    }
}

impl Writable for Triangle {
    fn write(&mut self, idx: u16, val: u8) {
        match idx % 4 {
            0 => self.length.write_halt(val),
            1 => (),
            2 => (),
            3 => self.length.write_counter(val),
            _ => (),
        }
    }
}

struct Noise {
    volume: u8,
    mode: u8,
    length: Length,
}

impl Noise {
    fn new() -> Noise {
        Noise {
            volume: 0,
            mode: 0,
            length: Length::new(5),
        }
    }
}

impl Writable for Noise {
    fn write(&mut self, idx: u16, val: u8) {
        match idx % 4 {
            0 => self.length.write_halt(val),
            1 => (),
            2 => (),
            3 => self.length.write_counter(val),
            _ => (),
        }
    }
}

struct DMC {
    freq: u8,
    direct: u8,
    sample_addr: u8,
    sample_length: u8,
}

impl DMC {
    fn new() -> DMC {
        DMC {
            freq: 0,
            direct: 0,
            sample_addr: 0,
            sample_length: 0,
        }
    }
}

impl Writable for DMC {
    fn write(&mut self, idx: u16, val: u8) {

    }
}

pub struct APU {
    pulse1: Pulse,
    pulse2: Pulse,
    triangle: Triangle,
    noise: Noise,
    dmc: DMC,
    frame: Frame,
    control: u8,
    status: u8,

    device: Box<AudioOut>,

    global_cyc: u64,
    tick: u64,
    next_tick_cyc: u64,
}

impl APU {
    pub fn new( device: Box<AudioOut> ) -> APU {
        APU {
            pulse1: Pulse::new(),
            pulse2: Pulse::new(),
            triangle: Triangle::new(),
            noise: Noise::new(),
            dmc: DMC::new(),
            frame: Frame::empty(),
            control: 0,
            status: 0,

            device: device,

            global_cyc: 0,
            tick: 0,
            next_tick_cyc: 0,
        }
    }

    pub fn run_to(&mut self, cpu_cycle: u64) {
        while self.global_cyc < cpu_cycle {
            if self.global_cyc == self.next_tick_cyc {
                self.tick();
                self.tick += 1;
                self.next_tick_cyc += if self.tick %2 == 0 {
                    CPU_CYCLES_PER_EVEN_TICK
                }
                else {
                    CPUCYCLES_PER_ODD_TICK
                }
            }
            self.global_cyc += 1;
        }
    }

    ///Represents the 240Hz output of the frame sequencer's divider
    fn tick(&mut self) {
        if !self.frame.contains(MODE) {
            match self.tick % 4 {
                0 => { self.envelope_tick(); },
                1 => { self.envelope_tick(); self.length_tick(); },
                2 => { self.envelope_tick(); },
                3 => { self.envelope_tick(); self.length_tick(); self.raise_irq(); },
                _ => (),
            }
        }
        else {
            match self.tick % 5 {
                0 => { self.envelope_tick(); self.length_tick() },
                1 => { self.envelope_tick(); },
                2 => { self.envelope_tick(); self.length_tick() },
                3 => { self.envelope_tick(); },
                4 => (),
                _ => (),
            }
        }
    }

    fn envelope_tick(&mut self) {

    }

    fn length_tick(&mut self) {
        self.pulse1.length.tick();
        self.pulse2.length.tick();
        self.triangle.length.tick();
        self.noise.length.tick();
    }

    fn raise_irq(&mut self) {

    }

    pub fn play(&mut self) {

    }
}

impl MemSegment for APU {
    fn read(&mut self, idx: u16) -> u8 {
        match idx % 0x20 {
            0x0015 => self.status,
            _ => 0,
        }
    }

    fn write(&mut self, idx: u16, val: u8) {
        match idx % 0x20 {
            x @ 0x00...0x03 => self.pulse1.write(x, val),
            x @ 0x04...0x07 => self.pulse2.write(x, val),
            x @ 0x08...0x0B => self.triangle.write(x, val),
            x @ 0x0C...0x0F => self.noise.write(x, val),
            x @ 0x10...0x13 => self.dmc.write(x, val),
            0x0014 => (),
            0x0015 => self.control = val,
            0x0016 => (),
            0x0017 => {
                self.frame = Frame::from_bits_truncate(val);
                self.tick = 0;
                if self.frame.contains( MODE ) {
                    //Trigger a tick immediately
                    self.next_tick_cyc = self.global_cyc
                }
                else {
                    //Reset the tick divider
                    self.next_tick_cyc = self.global_cyc + CPU_CYCLES_PER_EVEN_TICK
                }
            },
            _ => (),
        }
    }
}<|endoftext|>


<commit_before><commit_msg>define DNA and RNA<commit_after>pub enum Riboucleotide {
    A, C, G, U
}

pub enum Deoxyribonucleotide {
    A, C, G, T
}

#[allow(dead_code)]
type RNA = Vec<Riboucleotide>;

#[allow(dead_code)]
type DNA = Vec<Deoxyribonucleotide>;

pub fn parse_rna(input: &str) -> RNA {
    input.chars().map(|c: char| -> Riboucleotide {
        match c {
            'A' => Riboucleotide::A,
            'C' => Riboucleotide::C,
            'G' => Riboucleotide::G,
            'U' => Riboucleotide::U,
            _   => Riboucleotide::U,
        }
    }).collect()
}

pub fn parse_dna(input: &str) -> DNA {
    input.chars().map(|c: char| -> Deoxyribonucleotide {
        match c {
            'A' => Deoxyribonucleotide::A,
            'C' => Deoxyribonucleotide::C,
            'G' => Deoxyribonucleotide::G,
            'T' => Deoxyribonucleotide::T,
            _   => Deoxyribonucleotide::T,
        }
    }).collect()
}
<|endoftext|>


<commit_before>//! This exposes the command line interface that the binary uses
use std::fs;
use std::env;
use std::process;

use clap::{App, Arg, SubCommand};
use log;

use super::Result;
use super::sdk::{Sdk, SdkInfo, DumpOptions};
use super::config::Config;
use super::memdbstash::MemDbStash;

struct SimpleLogger;

impl log::Log for SimpleLogger {

    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Info
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}] {}: {}", record.level(),
                record.target(), record.args());
        }
    }
}

fn setup_logging() {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Warn);
        Box::new(SimpleLogger)
    }).unwrap();
}

/// Main entry point that starts the CLI
pub fn main() {
    setup_logging();
    match execute() {
        Ok(()) => {},
        Err(err) => {
            use std::error::Error;
            println!("error: {}", err);
            let mut cause = err.cause();
            while let Some(the_cause) = cause {
                println!("  caused by: {}", the_cause);
                cause = the_cause.cause();
            }
            process::exit(1);
        }
    }
}

fn execute() -> Result<()> {
    let app = App::new("SymbolServer")
        .author("Sentry")
        .about("Serves up apple system symbols")
        .arg(Arg::with_name("config")
             .long("config")
             .value_name("FILE")
             .help("The path to the config file"))
        .subcommand(
            SubCommand::with_name("sync-symbols"))
        .subcommand(
            SubCommand::with_name("convert-sdk")
                .about("Converts an SDK into a memdb file")
                .arg(Arg::with_name("path")
                     .index(1)
                     .value_name("PATH")
                     .required(true)
                     .multiple(true)
                     .help("Path to the support folder"))
                .arg(Arg::with_name("compress")
                     .short("c")
                     .long("compress")
                     .help("Write compressed files instead."))
                .arg(Arg::with_name("output-path")
                     .short("o")
                     .long("output")
                     .help("Where the result should be stored")));
    let matches = app.get_matches();

    let cfg = if let Some(config_path) = matches.value_of("config") {
        Config::load_file(config_path)?
    } else {
        Config::load_default()?
    };

    if let Some(matches) = matches.subcommand_matches("convert-sdk") {
        convert_sdk_action(matches.values_of("path").unwrap().collect(),
                           matches.value_of("output-path").unwrap_or("."),
                           matches.is_present("compress"))?;
    } else if let Some(_matches) = matches.subcommand_matches("sync-symbols") {
        sync_symbols_action(&cfg)?;
    }

    Ok(())
}

fn convert_sdk_action(paths: Vec<&str>, output_path: &str, compress: bool)
    -> Result<()>
{
    let dst_base = env::current_dir().unwrap().join(output_path);

    for (idx, path) in paths.iter().enumerate() {
        if idx > 0 {
            println!("");
        }
        let sdk = Sdk::new(&path)?;
        let mut dst = dst_base.join(&sdk.info().memdb_filename());
        if compress {
            dst.set_extension("memdbz");
        }

        println!("SDK {} ({} {}):", sdk.info().name(),
                 sdk.info().version(), sdk.info().build());

        // make sure we close the file at the end, in case we want to
        // re-open it for compressing.
        let f = fs::File::create(&dst)?;
        let options = DumpOptions {
            show_progress_bar: true,
            compress: compress,
            ..Default::default()
        };
        sdk.dump_memdb(f, options)?;
    }

    Ok(())
}

fn sync_symbols_action(config: &Config) -> Result<()> {
    let stash = MemDbStash::new(config)?;
    let status = stash.get_sync_status()?;
    println!("Sync healthy: {:?} (lag: {})", status.is_healthy(), status.lag());

    let info = SdkInfo::new("iOS", 10, 2, 1, "14D27");
    let memdb = stash.get_memdb(&info)?;
    println!("MemDB: {:?}", memdb.info());

    stash.sync()?;
    Ok(())
}
<commit_msg>Sync before load<commit_after>//! This exposes the command line interface that the binary uses
use std::fs;
use std::env;
use std::process;

use clap::{App, Arg, SubCommand};
use log;

use super::Result;
use super::sdk::{Sdk, SdkInfo, DumpOptions};
use super::config::Config;
use super::memdbstash::MemDbStash;

struct SimpleLogger;

impl log::Log for SimpleLogger {

    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Info
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}] {}: {}", record.level(),
                record.target(), record.args());
        }
    }
}

fn setup_logging() {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Warn);
        Box::new(SimpleLogger)
    }).unwrap();
}

/// Main entry point that starts the CLI
pub fn main() {
    setup_logging();
    match execute() {
        Ok(()) => {},
        Err(err) => {
            use std::error::Error;
            println!("error: {}", err);
            let mut cause = err.cause();
            while let Some(the_cause) = cause {
                println!("  caused by: {}", the_cause);
                cause = the_cause.cause();
            }
            process::exit(1);
        }
    }
}

fn execute() -> Result<()> {
    let app = App::new("SymbolServer")
        .author("Sentry")
        .about("Serves up apple system symbols")
        .arg(Arg::with_name("config")
             .long("config")
             .value_name("FILE")
             .help("The path to the config file"))
        .subcommand(
            SubCommand::with_name("sync-symbols"))
        .subcommand(
            SubCommand::with_name("convert-sdk")
                .about("Converts an SDK into a memdb file")
                .arg(Arg::with_name("path")
                     .index(1)
                     .value_name("PATH")
                     .required(true)
                     .multiple(true)
                     .help("Path to the support folder"))
                .arg(Arg::with_name("compress")
                     .short("c")
                     .long("compress")
                     .help("Write compressed files instead."))
                .arg(Arg::with_name("output-path")
                     .short("o")
                     .long("output")
                     .help("Where the result should be stored")));
    let matches = app.get_matches();

    let cfg = if let Some(config_path) = matches.value_of("config") {
        Config::load_file(config_path)?
    } else {
        Config::load_default()?
    };

    if let Some(matches) = matches.subcommand_matches("convert-sdk") {
        convert_sdk_action(matches.values_of("path").unwrap().collect(),
                           matches.value_of("output-path").unwrap_or("."),
                           matches.is_present("compress"))?;
    } else if let Some(_matches) = matches.subcommand_matches("sync-symbols") {
        sync_symbols_action(&cfg)?;
    }

    Ok(())
}

fn convert_sdk_action(paths: Vec<&str>, output_path: &str, compress: bool)
    -> Result<()>
{
    let dst_base = env::current_dir().unwrap().join(output_path);

    for (idx, path) in paths.iter().enumerate() {
        if idx > 0 {
            println!("");
        }
        let sdk = Sdk::new(&path)?;
        let mut dst = dst_base.join(&sdk.info().memdb_filename());
        if compress {
            dst.set_extension("memdbz");
        }

        println!("SDK {} ({} {}):", sdk.info().name(),
                 sdk.info().version(), sdk.info().build());

        // make sure we close the file at the end, in case we want to
        // re-open it for compressing.
        let f = fs::File::create(&dst)?;
        let options = DumpOptions {
            show_progress_bar: true,
            compress: compress,
            ..Default::default()
        };
        sdk.dump_memdb(f, options)?;
    }

    Ok(())
}

fn sync_symbols_action(config: &Config) -> Result<()> {
    let stash = MemDbStash::new(config)?;
    let status = stash.get_sync_status()?;
    println!("Sync healthy: {:?} (lag: {})", status.is_healthy(), status.lag());

    stash.sync()?;

    let info = SdkInfo::new("iOS", 10, 2, 1, "14D27");
    let memdb = stash.get_memdb(&info)?;
    println!("MemDB: {:?}", memdb.info());

    Ok(())
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::env;
use std::marker::PhantomData;
use std::path::Path;
use clap::{self, Arg, SubCommand};
use shlex;

use app::{ClapApp, ClapRun};
use core::{Query, Repository, Workspace};
use util;
use vcs::{self, Vcs};
use core::url::build_url;

/// Toplevel application
pub enum Command<'a> {
  New(NewCommand<'a>),
  Add(AddCommand<'a>),
  Clone(CloneCommand<'a>),
  Scan(ScanCommand<'a>),
  List(ListCommand<'a>),
  Foreach(ForeachCommand<'a>),
}

impl<'a> ClapApp for Command<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.subcommand(NewCommand::make_app(SubCommand::with_name("new")))
       .subcommand(AddCommand::make_app(SubCommand::with_name("add")))
       .subcommand(CloneCommand::make_app(SubCommand::with_name("clone")))
       .subcommand(ListCommand::make_app(SubCommand::with_name("list")))
       .subcommand(ForeachCommand::make_app(SubCommand::with_name("foreach")))
       .subcommand(ScanCommand::make_app(SubCommand::with_name("scan")))
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for Command<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> Command<'a> {
    match m.subcommand() {
      ("new", Some(m)) => Command::New(m.into()),
      ("add", Some(m)) => Command::Add(m.into()),
      ("clone", Some(m)) => Command::Clone(m.into()),
      ("list", Some(m)) => Command::List(m.into()),
      ("foreach", Some(m)) => Command::Foreach(m.into()),
      ("scan", Some(m)) => Command::Scan(m.into()),
      _ => unreachable!(),
    }
  }
}

impl<'a> Command<'a> {
  pub fn run(self) -> ::Result<()> {
    match self {
      Command::New(m) => m.run(),
      Command::Add(m) => m.run(),
      Command::Clone(m) => m.run(),
      Command::List(m) => m.run(),
      Command::Foreach(m) => m.run(),
      Command::Scan(m) => m.run(),
    }
  }
}

pub struct AddCommand<'a> {
  path: Option<&'a Path>,
}

impl<'a> ClapApp for AddCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Add existed repository under management")
       .arg_from_usage("[path]  'Path of local repository'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for AddCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> AddCommand<'a> {
    AddCommand { path: m.value_of("path").map(Path::new) }
  }
}

impl<'a> ClapRun for AddCommand<'a> {
  fn run(self) -> ::Result<()> {
    let mut workspace = Workspace::new(None)?;

    let path = self.path
                   .map(|path| if path.is_absolute() {
                          Ok(path.to_owned())
                        } else {
                          env::current_dir().map(|cwd| cwd.join(path))
                        })
                   .unwrap_or_else(|| env::current_dir())?;

    let repo = Repository::from_path(path)?;
    if !repo.is_vcs() {
      Err("Given path is not a repository")?;
    }
    workspace.add_repository(repo);
    workspace.save_cache()?;

    Ok(())
  }
}

/// Subcommand `new`
pub struct NewCommand<'a> {
  query: Query,
  root: Option<&'a Path>,
  dry_run: bool,
  vcs: Option<Vcs>,
}

impl<'a> ClapApp for NewCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Create a new Git repository with intuitive directory structure")
       .arg_from_usage("<query>          'URL or query of remote repository'")
       .arg_from_usage("--root=[root]    'Target root directory of repository")
       .arg_from_usage("-n, --dry-run    'Do not actually create a new repository'")
       .arg(Arg::from_usage("--vcs=[vcs] 'Used Version Control System'").possible_values(Vcs::possible_values()))
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for NewCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> NewCommand<'a> {
    NewCommand {
      query: m.value_of("query")
              .and_then(|s| s.parse().ok())
              .unwrap(),
      root: m.value_of("root").map(Path::new),
      dry_run: m.is_present("dry-run"),
      vcs: m.value_of("vcs").and_then(|s| s.parse().ok()),
    }
  }
}

impl<'a> ClapRun for NewCommand<'a> {
  fn run(self) -> ::Result<()> {
    let mut workspace = Workspace::new(self.root)?;

    let dest = {
      let host = self.query.host().unwrap_or("github.com");
      let path = self.query.path();
      workspace.root_dir()
               .ok_or("Unknown root directory")?
               .join(host)
               .join(path.borrow() as &str)
    };
    if vcs::detect_from_path(&dest).is_some() {
      println!("The repository {} has already existed.", dest.display());
      return Ok(());
    }

    let vcs = self.vcs.unwrap_or(Vcs::Git);

    print!("Creating an empty repository at \"{}\"", dest.display());
    print!(" (VCS: {:?})", vcs);
    println!();

    if !self.dry_run {
      vcs.do_init(&dest)?;
      let repo = Repository::from_path(dest)?;
      workspace.add_repository(repo);
      workspace.save_cache()?;
    }

    Ok(())
  }
}

/// Subcommand `clone`
pub struct CloneCommand<'a> {
  query: Query,
  root: Option<&'a Path>,
  arg: Option<&'a str>,
  dry_run: bool,
  ssh: bool,
  vcs: Option<Vcs>,
}

impl<'a> ClapApp for CloneCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Clone remote repositories into the root directory")
       .arg_from_usage("<query>         'URL or query of remote repository'")
       .arg_from_usage("--root=[root]   'Target root directory of cloned repository'")
       .arg_from_usage("--arg=[arg]     'Supplemental arguments for Git command'")
       .arg_from_usage("-n, --dry-run   'Do not actually execute Git command'")
       .arg_from_usage("-s, --ssh       'Use SSH protocol'")
       .arg(Arg::from_usage("--vcs=[vcs] 'Used Version Control System'").possible_values(Vcs::possible_values()))
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for CloneCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> CloneCommand<'a> {
    CloneCommand {
      query: m.value_of("query")
              .and_then(|s| s.parse().ok())
              .unwrap(),
      root: m.value_of("root").map(Path::new),
      arg: m.value_of("arg"),
      dry_run: m.is_present("dry-run"),
      ssh: m.is_present("ssh"),
      vcs: m.value_of("vcs").and_then(|s| s.parse().ok()),
    }
  }
}

impl<'a> ClapRun for CloneCommand<'a> {
  fn run(self) -> ::Result<()> {
    let mut workspace = Workspace::new(self.root)?;

    let dest = {
      let host = self.query.host().unwrap_or("github.com");
      let path = self.query.path();
      workspace.root_dir()
               .ok_or("Unknown root directory")?
               .join(host)
               .join(path.borrow() as &str)
    };
    if vcs::detect_from_path(&dest).is_some() {
      println!("The repository {} has already existed.", dest.display());
      return Ok(());
    }

    let url = build_url(&self.query, self.ssh)?;

    let args = self.arg
                   .and_then(|s| shlex::split(s))
                   .unwrap_or_default();

    let vcs = self.vcs.unwrap_or(Vcs::Git);

    println!("Clone: \"{}\" \"{}\" {}, {:?}",
             url,
             dest.display(),
             util::join_str(&args),
             vcs);

    if !self.dry_run {
      vcs.do_clone(&dest, &url, &args)?;

      let mut repo = Repository::from_path(dest)?;
      repo.set_url(url);
      workspace.add_repository(repo);
      workspace.save_cache()?;
    }

    Ok(())
  }
}

/// Subcommand `scan`
pub struct ScanCommand<'a> {
  verbose: bool,
  prune: bool,
  depth: Option<usize>,
  marker: PhantomData<&'a usize>,
}

impl<'a> ClapApp for ScanCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Scan directories to create cache of repositories list")
       .arg_from_usage("-v, --verbose    'Use verbose output'")
       .arg_from_usage("-p, --prune      'Ignore repositories located at outside of base directories'")
       .arg_from_usage("--depth=[depth]  'Maximal depth of entries for each base directory'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for ScanCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> ScanCommand<'a> {
    ScanCommand {
      verbose: m.is_present("verbose"),
      prune: m.is_present("prune"),
      depth: m.value_of("depth").and_then(|s| s.parse().ok()),
      marker: PhantomData,
    }
  }
}

impl<'a> ClapRun for ScanCommand<'a> {
  fn run(self) -> ::Result<()> {
    let mut workspace = Workspace::new(None)?;
    workspace.scan_repositories(self.verbose, self.prune, self.depth)?;
    workspace.save_cache()?;
    Ok(())
  }
}

/// Subcommand `list`
pub struct ListCommand<'a> {
  marker: PhantomData<&'a usize>,
}

impl<'a> ClapApp for ListCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("List local repositories managed by rhq")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for ListCommand<'a> {
  fn from(_: &'b clap::ArgMatches<'a>) -> ListCommand<'a> {
    ListCommand { marker: PhantomData }
  }
}

impl<'a> ClapRun for ListCommand<'a> {
  fn run(self) -> ::Result<()> {
    let workspace = Workspace::new(None)?;
    let repos = workspace.repositories()
                         .ok_or("The cache has not initialized yet")?;
    for repo in repos {
      println!("{}", repo.path_string());
    }
    Ok(())
  }
}

/// Subcommand `foreach`
pub struct ForeachCommand<'a> {
  command: &'a str,
  args: Option<clap::Values<'a>>,
  dry_run: bool,
}

impl<'a> ClapApp for ForeachCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Execute command into each repositories")
       .arg_from_usage("<command>       'Command name'")
       .arg_from_usage("[args]...       'Arguments of command'")
       .arg_from_usage("-n, --dry-run   'Do not actually execute command'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for ForeachCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> ForeachCommand<'a> {
    ForeachCommand {
      command: m.value_of("command").unwrap(),
      args: m.values_of("args"),
      dry_run: m.is_present("dry-run"),
    }
  }
}

impl<'a> ClapRun for ForeachCommand<'a> {
  fn run(self) -> ::Result<()> {
    let args: Vec<_> = self.args.map(|s| s.collect()).unwrap_or_default();
    let workspace = Workspace::new(None)?;
    let repos = workspace.repositories()
                         .ok_or("The cache has not initialized yet")?;
    for repo in repos {
      if self.dry_run {
        println!("+ {} {}", self.command, util::join_str(&args));
      } else {
        repo.run_command(self.command, &args)?;
      }
    }
    Ok(())
  }
}
<commit_msg>move subcommand: new => init<commit_after>use std::borrow::{Borrow, Cow};
use std::env;
use std::marker::PhantomData;
use std::path::Path;
use clap::{self, Arg, SubCommand};
use shlex;

use app::{ClapApp, ClapRun};
use core::{Query, Repository, Workspace};
use util;
use vcs::{self, Vcs};
use core::url::build_url;

/// Toplevel application
pub enum Command<'a> {
  Init(InitCommand<'a>),
  Add(AddCommand<'a>),
  Clone(CloneCommand<'a>),
  Scan(ScanCommand<'a>),
  List(ListCommand<'a>),
  Foreach(ForeachCommand<'a>),
}

impl<'a> ClapApp for Command<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.subcommand(InitCommand::make_app(SubCommand::with_name("init")))
       .subcommand(AddCommand::make_app(SubCommand::with_name("add")))
       .subcommand(CloneCommand::make_app(SubCommand::with_name("clone")))
       .subcommand(ListCommand::make_app(SubCommand::with_name("list")))
       .subcommand(ForeachCommand::make_app(SubCommand::with_name("foreach")))
       .subcommand(ScanCommand::make_app(SubCommand::with_name("scan")))
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for Command<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> Command<'a> {
    match m.subcommand() {
      ("init", Some(m)) => Command::Init(m.into()),
      ("add", Some(m)) => Command::Add(m.into()),
      ("clone", Some(m)) => Command::Clone(m.into()),
      ("list", Some(m)) => Command::List(m.into()),
      ("foreach", Some(m)) => Command::Foreach(m.into()),
      ("scan", Some(m)) => Command::Scan(m.into()),
      _ => unreachable!(),
    }
  }
}

impl<'a> Command<'a> {
  pub fn run(self) -> ::Result<()> {
    match self {
      Command::Init(m) => m.run(),
      Command::Add(m) => m.run(),
      Command::Clone(m) => m.run(),
      Command::List(m) => m.run(),
      Command::Foreach(m) => m.run(),
      Command::Scan(m) => m.run(),
    }
  }
}

pub struct AddCommand<'a> {
  path: Option<&'a Path>,
}

impl<'a> ClapApp for AddCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Add existed repository under management")
       .arg_from_usage("[path]  'Path of local repository'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for AddCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> AddCommand<'a> {
    AddCommand { path: m.value_of("path").map(Path::new) }
  }
}

impl<'a> ClapRun for AddCommand<'a> {
  fn run(self) -> ::Result<()> {
    let path: Cow<Path> = {
      self.path
          .map(Into::into)
          .map(Result::Ok)
          .unwrap_or_else(|| env::current_dir().map(Into::into))?
    };
    if vcs::detect_from_path(&path).is_none() {
      Err("Given path is not a repository")?;
    }

    let repo = Repository::from_path(path)?;

    let mut workspace = Workspace::new(None)?;
    workspace.add_repository(repo);
    workspace.save_cache()?;

    Ok(())
  }
}

/// Subcommand `new`
pub struct InitCommand<'a> {
  path: Option<&'a Path>,
  vcs: Option<Vcs>,
  posthook: Option<&'a str>,
  dry_run: bool,
}

use util::process;

impl<'a> ClapApp for InitCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Create a new Git repository with intuitive directory structure")
       .arg_from_usage("[path]                'Path of target repository (current directory by default)'")
       .arg(Arg::from_usage("--vcs=[vcs]      'Used Version Control System'")
              .possible_values(Vcs::possible_values()))
       .arg_from_usage("--posthook=[posthook] 'Post hook after initialization'")
       .arg_from_usage("-n, --dry-run         'Do not actually perform commands'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for InitCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> InitCommand<'a> {
    InitCommand {
      path: m.value_of("path").map(Path::new),
      vcs: m.value_of("vcs").and_then(|s| s.parse().ok()),
      posthook: m.value_of("posthook"),
      dry_run: m.is_present("dry-run"),
    }
  }
}

impl<'a> ClapRun for InitCommand<'a> {
  fn run(self) -> ::Result<()> {
    let path: Cow<Path> = {
      self.path
          .map(Into::into)
          .map(Result::Ok)
          .unwrap_or_else(|| env::current_dir().map(Into::into))?
    };
    if vcs::detect_from_path(&path).is_some() {
      println!("The repository {} has already existed.", path.display());
      return Ok(());
    }

    let vcs = self.vcs.unwrap_or(Vcs::Git);

    let posthook = self.posthook.and_then(|s| shlex::split(s));

    print!("Creating an empty repository at \"{}\"", path.display());
    print!(" (VCS: {:?})", vcs);
    println!();

    if !self.dry_run {
      vcs.do_init(&path)?;
      if let Some(posthook) = posthook {
        if posthook.len() >= 1 {
          let command = posthook[0].clone();
          let args: Vec<_> = posthook.into_iter().skip(1).collect();
          process::inherit(&command).args(args)
            .current_dir(&path)
            .status()?;
        }
      }

      let repo = Repository::from_path(path)?;

      let mut workspace = Workspace::new(None)?;
      workspace.add_repository(repo);
      workspace.save_cache()?;
    }

    Ok(())
  }
}

/// Subcommand `clone`
pub struct CloneCommand<'a> {
  query: Query,
  root: Option<&'a Path>,
  arg: Option<&'a str>,
  dry_run: bool,
  ssh: bool,
  vcs: Option<Vcs>,
}

impl<'a> ClapApp for CloneCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Clone remote repositories into the root directory")
       .arg_from_usage("<query>         'URL or query of remote repository'")
       .arg_from_usage("--root=[root]   'Target root directory of cloned repository'")
       .arg_from_usage("--arg=[arg]     'Supplemental arguments for Git command'")
       .arg_from_usage("-n, --dry-run   'Do not actually execute Git command'")
       .arg_from_usage("-s, --ssh       'Use SSH protocol'")
       .arg(Arg::from_usage("--vcs=[vcs] 'Used Version Control System'").possible_values(Vcs::possible_values()))
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for CloneCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> CloneCommand<'a> {
    CloneCommand {
      query: m.value_of("query")
              .and_then(|s| s.parse().ok())
              .unwrap(),
      root: m.value_of("root").map(Path::new),
      arg: m.value_of("arg"),
      dry_run: m.is_present("dry-run"),
      ssh: m.is_present("ssh"),
      vcs: m.value_of("vcs").and_then(|s| s.parse().ok()),
    }
  }
}

impl<'a> ClapRun for CloneCommand<'a> {
  fn run(self) -> ::Result<()> {
    let mut workspace = Workspace::new(self.root)?;

    let dest = {
      let host = self.query.host().unwrap_or("github.com");
      let path = self.query.path();
      workspace.root_dir()
               .ok_or("Unknown root directory")?
               .join(host)
               .join(path.borrow() as &str)
    };
    if vcs::detect_from_path(&dest).is_some() {
      println!("The repository {} has already existed.", dest.display());
      return Ok(());
    }

    let url = build_url(&self.query, self.ssh)?;

    let args = self.arg
                   .and_then(|s| shlex::split(s))
                   .unwrap_or_default();

    let vcs = self.vcs.unwrap_or(Vcs::Git);

    println!("Clone: \"{}\" \"{}\" {}, {:?}",
             url,
             dest.display(),
             util::join_str(&args),
             vcs);

    if !self.dry_run {
      vcs.do_clone(&dest, &url, &args)?;

      let mut repo = Repository::from_path(dest)?;
      repo.set_url(url);
      workspace.add_repository(repo);
      workspace.save_cache()?;
    }

    Ok(())
  }
}

/// Subcommand `scan`
pub struct ScanCommand<'a> {
  verbose: bool,
  prune: bool,
  depth: Option<usize>,
  marker: PhantomData<&'a usize>,
}

impl<'a> ClapApp for ScanCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Scan directories to create cache of repositories list")
       .arg_from_usage("-v, --verbose    'Use verbose output'")
       .arg_from_usage("-p, --prune      'Ignore repositories located at outside of base directories'")
       .arg_from_usage("--depth=[depth]  'Maximal depth of entries for each base directory'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for ScanCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> ScanCommand<'a> {
    ScanCommand {
      verbose: m.is_present("verbose"),
      prune: m.is_present("prune"),
      depth: m.value_of("depth").and_then(|s| s.parse().ok()),
      marker: PhantomData,
    }
  }
}

impl<'a> ClapRun for ScanCommand<'a> {
  fn run(self) -> ::Result<()> {
    let mut workspace = Workspace::new(None)?;
    workspace.scan_repositories(self.verbose, self.prune, self.depth)?;
    workspace.save_cache()?;
    Ok(())
  }
}

/// Subcommand `list`
pub struct ListCommand<'a> {
  marker: PhantomData<&'a usize>,
}

impl<'a> ClapApp for ListCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("List local repositories managed by rhq")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for ListCommand<'a> {
  fn from(_: &'b clap::ArgMatches<'a>) -> ListCommand<'a> {
    ListCommand { marker: PhantomData }
  }
}

impl<'a> ClapRun for ListCommand<'a> {
  fn run(self) -> ::Result<()> {
    let workspace = Workspace::new(None)?;
    let repos = workspace.repositories()
                         .ok_or("The cache has not initialized yet")?;
    for repo in repos {
      println!("{}", repo.path_string());
    }
    Ok(())
  }
}

/// Subcommand `foreach`
pub struct ForeachCommand<'a> {
  command: &'a str,
  args: Option<clap::Values<'a>>,
  dry_run: bool,
}

impl<'a> ClapApp for ForeachCommand<'a> {
  fn make_app<'b, 'c: 'b>(app: clap::App<'b, 'c>) -> clap::App<'b, 'c> {
    app.about("Execute command into each repositories")
       .arg_from_usage("<command>       'Command name'")
       .arg_from_usage("[args]...       'Arguments of command'")
       .arg_from_usage("-n, --dry-run   'Do not actually execute command'")
  }
}

impl<'a, 'b: 'a> From<&'b clap::ArgMatches<'a>> for ForeachCommand<'a> {
  fn from(m: &'b clap::ArgMatches<'a>) -> ForeachCommand<'a> {
    ForeachCommand {
      command: m.value_of("command").unwrap(),
      args: m.values_of("args"),
      dry_run: m.is_present("dry-run"),
    }
  }
}

impl<'a> ClapRun for ForeachCommand<'a> {
  fn run(self) -> ::Result<()> {
    let args: Vec<_> = self.args.map(|s| s.collect()).unwrap_or_default();
    let workspace = Workspace::new(None)?;
    let repos = workspace.repositories()
                         .ok_or("The cache has not initialized yet")?;
    for repo in repos {
      if self.dry_run {
        println!("+ {} {}", self.command, util::join_str(&args));
      } else {
        repo.run_command(self.command, &args)?;
      }
    }
    Ok(())
  }
}
<|endoftext|>