<commit_before>use rustc::lint::*;
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
use rustc::ty;
use rustc::hir::*;
use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then};

/// **What it does:** This lint checks for transmutes to the original type of the object.
///
/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type.
///
/// **Known problems:** None.
///
/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `t`'s.
declare_lint! {
    pub USELESS_TRANSMUTE,
    Warn,
    "transmutes that have the same to and from types"
}

/// **What it does:*** This lint checks for transmutes between a type `T` and `*T`.
///
/// **Why is this bad?** It's easy to mistakenly transmute between a type and a pointer to that type.
///
/// **Known problems:** None.
///
/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `*t` or `&t`'s.
declare_lint! {
    pub CROSSPOINTER_TRANSMUTE,
    Warn,
    "transmutes that have to or from types that are a pointer to the other"
}

/// **What it does:*** This lint checks for transmutes from a pointer to a reference.
///
/// **Why is this bad?** This can always be rewritten with `&` and `*`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let _: &T = std::mem::transmute(p); // where p: *const T
/// // can be written:
/// let _: &T = &*p;
/// ```
declare_lint! {
    pub TRANSMUTE_PTR_TO_REF,
    Warn,
    "transmutes from a pointer to a reference type"
}

pub struct Transmute;

impl LintPass for Transmute {
    fn get_lints(&self) -> LintArray {
        lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE]
    }
}

impl LateLintPass for Transmute {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprCall(ref path_expr, ref args) = e.node {
            if let ExprPath(None, _) = path_expr.node {
                let def_id = cx.tcx.expect_def(path_expr.id).def_id();

                if match_def_path(cx, def_id, &paths::TRANSMUTE) {
                    let from_ty = cx.tcx.expr_ty(&args[0]);
                    let to_ty = cx.tcx.expr_ty(e);

                    if from_ty == to_ty {
                        span_lint(cx,
                                  USELESS_TRANSMUTE,
                                  e.span,
                                  &format!("transmute from a type (`{}`) to itself", from_ty));
                    } else if is_ptr_to(to_ty, from_ty) {
                        span_lint(cx,
                                  CROSSPOINTER_TRANSMUTE,
                                  e.span,
                                  &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)",
                                           from_ty,
                                           to_ty));
                    } else if is_ptr_to(from_ty, to_ty) {
                        span_lint(cx,
                                  CROSSPOINTER_TRANSMUTE,
                                  e.span,
                                  &format!("transmute from a type (`{}`) to the type that it points to (`{}`)",
                                           from_ty,
                                           to_ty));
                    } else {
                        check_ptr_to_ref(cx, from_ty, to_ty, e, &args[0]);
                    }
                }
            }
        }
    }
}

fn is_ptr_to(from: ty::Ty, to: ty::Ty) -> bool {
    if let TyRawPtr(from_ptr) = from.sty {
        from_ptr.ty == to
    } else {
        false
    }
}

fn check_ptr_to_ref<'tcx>(cx: &LateContext, from_ty: ty::Ty<'tcx>, to_ty: ty::Ty<'tcx>, e: &Expr, arg: &Expr) {
    if let TyRawPtr(ref from_pty) = from_ty.sty {
        if let TyRef(_, ref to_rty) = to_ty.sty {
            let mess = format!("transmute from a pointer type (`{}`) to a reference type (`{}`)",
                               from_ty,
                               to_ty);
            span_lint_and_then(cx, TRANSMUTE_PTR_TO_REF, e.span, &mess, |db| {
                if let Some(arg) = snippet_opt(cx, arg.span) {
                    let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable {
                        ("&mut *", "*mut")
                    } else {
                        ("&*", "*const")
                    };

                    let sugg = if from_pty.ty == to_rty.ty {
                        format!("{}{}", deref, arg)
                    } else {
                        format!("{}({} as {} {})", deref, arg, cast, to_rty.ty)
                    };

                    db.span_suggestion(e.span, "try", sugg);
                }
            });
        }
    }
}
<commit_msg>refactor transmute lints into a single match<commit_after>use rustc::lint::*;
use rustc::ty::TypeVariants::{TyRawPtr, TyRef};
use rustc::hir::*;
use utils::{match_def_path, paths, snippet_opt, span_lint, span_lint_and_then};

/// **What it does:** This lint checks for transmutes to the original type of the object.
///
/// **Why is this bad?** Readability. The code tricks people into thinking that the original value was of some other type.
///
/// **Known problems:** None.
///
/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `t`'s.
declare_lint! {
    pub USELESS_TRANSMUTE,
    Warn,
    "transmutes that have the same to and from types"
}

/// **What it does:*** This lint checks for transmutes between a type `T` and `*T`.
///
/// **Why is this bad?** It's easy to mistakenly transmute between a type and a pointer to that type.
///
/// **Known problems:** None.
///
/// **Example:** `core::intrinsics::transmute(t)` where the result type is the same as `*t` or `&t`'s.
declare_lint! {
    pub CROSSPOINTER_TRANSMUTE,
    Warn,
    "transmutes that have to or from types that are a pointer to the other"
}

/// **What it does:*** This lint checks for transmutes from a pointer to a reference.
///
/// **Why is this bad?** This can always be rewritten with `&` and `*`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let _: &T = std::mem::transmute(p); // where p: *const T
/// // can be written:
/// let _: &T = &*p;
/// ```
declare_lint! {
    pub TRANSMUTE_PTR_TO_REF,
    Warn,
    "transmutes from a pointer to a reference type"
}

pub struct Transmute;

impl LintPass for Transmute {
    fn get_lints(&self) -> LintArray {
        lint_array![CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE]
    }
}

impl LateLintPass for Transmute {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprCall(ref path_expr, ref args) = e.node {
            if let ExprPath(None, _) = path_expr.node {
                let def_id = cx.tcx.expect_def(path_expr.id).def_id();

                if match_def_path(cx, def_id, &paths::TRANSMUTE) {
                    let from_ty = cx.tcx.expr_ty(&args[0]);
                    let to_ty = cx.tcx.expr_ty(e);

                    match (&from_ty.sty, &to_ty.sty) {
                        _ if from_ty == to_ty => span_lint(
                            cx,
                            USELESS_TRANSMUTE,
                            e.span,
                            &format!("transmute from a type (`{}`) to itself", from_ty),
                        ),
                        (&TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
                            cx,
                            CROSSPOINTER_TRANSMUTE,
                            e.span,
                            &format!("transmute from a type (`{}`) to the type that it points to (`{}`)",
                                     from_ty,
                                     to_ty),
                        ),
                        (_, &TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint(
                            cx,
                            CROSSPOINTER_TRANSMUTE,
                            e.span,
                            &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)",
                                     from_ty,
                                     to_ty),
                        ),
                        (&TyRawPtr(from_pty), &TyRef(_, to_rty)) => span_lint_and_then(
                            cx,
                            TRANSMUTE_PTR_TO_REF,
                            e.span,
                            &format!("transmute from a pointer type (`{}`) to a reference type (`{}`)",
                                    from_ty,
                                    to_ty),
                            |db| {
                                if let Some(arg) = snippet_opt(cx, args[0].span) {
                                    let (deref, cast) = if to_rty.mutbl == Mutability::MutMutable {
                                        ("&mut *", "*mut")
                                    } else {
                                        ("&*", "*const")
                                    };

                                    let sugg = if from_pty.ty == to_rty.ty {
                                        format!("{}{}", deref, arg)
                                    } else {
                                        format!("{}({} as {} {})", deref, arg, cast, to_rty.ty)
                                    };

                                    db.span_suggestion(e.span, "try", sugg);
                                }
                            },
                        ),
                        _ => return,
                    };
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::context::*;
use super::instance::*;
use super::register::*;
use super::signal::*;
use super::value::*;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::ptr;

/// A self-contained and potentially-reusable hardware design unit, created by the [`Context`]::[`module`] method.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("my_module");
/// m.output("out", m.input("in", 1));
/// ```
///
/// [`Context`]: ./struct.Context.html
/// [`module`]: ./struct.Context.html#method.module
#[must_use]
pub struct Module<'a> {
    context: &'a Context<'a>,

    pub(crate) name: String,

    pub(crate) inputs: RefCell<BTreeMap<String, &'a Signal<'a>>>,
    pub(crate) outputs: RefCell<BTreeMap<String, &'a Signal<'a>>>,
    pub(crate) registers: RefCell<Vec<&'a Signal<'a>>>,
    pub(crate) instances: RefCell<Vec<&'a Instance<'a>>>,
}

impl<'a> Module<'a> {
    pub(super) fn new(context: &'a Context<'a>, name: String) -> Module<'a> {
        Module {
            context,

            name,

            inputs: RefCell::new(BTreeMap::new()),
            outputs: RefCell::new(BTreeMap::new()),
            registers: RefCell::new(Vec::new()),
            instances: RefCell::new(Vec::new()),
        }
    }

    /// Creates a [`Signal`] that represents the constant literal specified by `value` with `bit_width` bits.
    ///
    /// The bit width of the type provided by `value` doesn't need to match `bit_width`. but the value represented by `value` must fit into `bit_width` bits.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively, or if the specified `value` doesn't fit into `bit_width` bits.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let eight_bit_const = m.lit(0xffu32, 8);
    /// let one_bit_const = m.lit(0u32, 1);
    /// let twenty_seven_bit_const = m.lit(true, 27);
    /// ```
    ///
    /// [`MIN_SIGNAL_BIT_WIDTH`]: ./constant.MIN_SIGNAL_BIT_WIDTH.html
    /// [`MAX_SIGNAL_BIT_WIDTH`]: ./constant.MAX_SIGNAL_BIT_WIDTH.html
    /// [`Signal`]: ./struct.Signal.html
    pub fn lit<V: Into<Value>>(&'a self, value: V, bit_width: u32) -> &Signal<'a> {
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a literal with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a literal with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let value = value.into();
        let required_bits = value.required_bits();
        if required_bits > bit_width {
            let numeric_value = value.numeric_value();
            panic!("Cannot fit the specified value '{}' into the specified bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, bit_width, numeric_value, required_bits);
        }
        self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Lit { value, bit_width },
        })
    }

    /// Convenience method to create a [`Signal`] that represents a single `0` bit.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// // The following two signals are semantically equivalent:
    /// let low1 = m.low();
    /// let low2 = m.lit(false, 1);
    /// ```
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub fn low(&'a self) -> &Signal<'a> {
        self.lit(false, 1)
    }

    /// Convenience method to create a [`Signal`] that represents a single `1` bit.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// // The following two signals are semantically equivalent:
    /// let high1 = m.high();
    /// let high2 = m.lit(true, 1);
    /// ```
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub fn high(&'a self) -> &Signal<'a> {
        self.lit(true, 1)
    }

    /// Creates an input for this `Module` called `name` with `bit_width` bits, and returns a [`Signal`] that represents the value of this input.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_input = m.input("my_input", 80);
    /// ```
    ///
    /// [`MIN_SIGNAL_BIT_WIDTH`]: ./constant.MIN_SIGNAL_BIT_WIDTH.html
    /// [`MAX_SIGNAL_BIT_WIDTH`]: ./constant.MAX_SIGNAL_BIT_WIDTH.html
    /// [`Signal`]: ./struct.Signal.html
    pub fn input<S: Into<String>>(&'a self, name: S, bit_width: u32) -> &Signal<'a> {
        let name = name.into();
        // TODO: Error if name already exists in this context
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create an input with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create an input with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let input = self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Input {
                name: name.clone(),
                bit_width,
            },
        });
        self.inputs.borrow_mut().insert(name, input);
        input
    }

    /// Creates an output for this `Module` called `name` with the same number of bits as `source`, and drives this output with `source`.
    ///
    /// # Panics
    ///
    /// Panics of `source` doesn't belong to this `Module`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let some_signal = m.high();
    /// m.output("my_output", some_signal);
    /// ```
    pub fn output<S: Into<String>>(&'a self, name: S, source: &'a Signal<'a>) {
        if !ptr::eq(self, source.module) {
            panic!("Cannot output a signal from another module.");
        }
        // TODO: Error if name already exists in this context
        self.outputs.borrow_mut().insert(name.into(), source);
    }

    pub fn reg<S: Into<String>>(&'a self, name: S, bit_width: u32) -> &Register<'a> {
        // TODO: bit_width bounds checks
        // TODO: Ensure initial_value fits within bit_width bits
        // TODO: Error if name already exists in this context
        let data = self.context.register_data_arena.alloc(RegisterData {
            name: name.into(),
            initial_value: RefCell::new(None),
            bit_width,
            next: RefCell::new(None),
        });
        let value = self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Reg { data },
        });
        self.registers.borrow_mut().push(value);
        self.context.register_arena.alloc(Register { data, value })
    }

    pub fn mux(
        &'a self,
        cond: &'a Signal<'a>,
        when_true: &'a Signal<'a>,
        when_false: &'a Signal<'a>,
    ) -> &Signal<'a> {
        // TODO: This is an optimization to support kaze_sugar; if that doesn't go well, remove this
        if ptr::eq(when_true, when_false) {
            return when_true;
        }

        // TODO: Ensure when_true and when_false have the same bit widths
        // TODO: Ensure sel is 1 bit wide
        self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Mux {
                cond,
                when_true,
                when_false,
            },
        })
    }

    /// Instantiates the `Module` identified by `module_name` in this [`Context`] inside this `Module` definition called `instance_name`, and returns the new [`Instance`].
    ///
    /// # Panics
    ///
    /// Panics if a `Module` identified by `module_name` doesn't exist in this [`Context`].
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// // Inner module (simple pass-through)
    /// let inner = c.module("inner");
    /// inner.output("o", inner.input("i", 32));
    ///
    /// // Outer module (wraps a single `inner` instance)
    /// let outer = c.module("outer");
    /// let inner_inst = outer.instance("inner", "inner_inst");
    /// inner_inst.drive_input("i", outer.input("i", 32));
    /// outer.output("o", inner_inst.output("o"));
    /// ```
    ///
    /// [`Context`]: ./struct.Context.html
    /// [`Instance`]: ./struct.Instance.html
    pub fn instance<S: Into<String>>(
        &'a self,
        module_name: &str,
        instance_name: S,
    ) -> &Instance<'a> {
        // TODO: Error if instance_name already exists in this context
        match self.context.modules.borrow().get(module_name) {
            Some(instantiated_module) => {
                let ret = self.context.instance_arena.alloc(Instance {
                    context: self.context,
                    module: self,

                    instantiated_module,
                    name: instance_name.into(),
                    driven_inputs: RefCell::new(BTreeMap::new()),
                });
                self.instances.borrow_mut().push(ret);
                ret
            }
            _ => panic!("Attempted to instantiate a module identified by \"{}\", but no such module exists in this context.", module_name)
        }
    }
}

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

    #[test]
    #[should_panic(
        expected = "Cannot create a literal with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn lit_bit_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(false, 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a literal with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn lit_bit_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(false, 129);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into the specified bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_1() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(128u32, 7);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into the specified bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_2() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(128u64, 2);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '1023' into the specified bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_3() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(1023u128, 4);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '65536' into the specified bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_4() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(65536u32, 1);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create an input with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn input_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.input("i", 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create an input with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn input_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.input("i", 129);
    }

    #[test]
    #[should_panic(expected = "Cannot output a signal from another module.")]
    fn output_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a");

        let m2 = c.module("b");
        let i = m2.high();

        // Panic
        m1.output("a", i);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to instantiate a module identified by \"nope\", but no such module exists in this context."
    )]
    fn instantiate_nonexistent_module_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.instance("nope", "lol");
    }
}
<commit_msg>Document Module::reg<commit_after>use super::context::*;
use super::instance::*;
use super::register::*;
use super::signal::*;
use super::value::*;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::ptr;

/// A self-contained and potentially-reusable hardware design unit, created by the [`Context`]::[`module`] method.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("my_module");
/// m.output("out", m.input("in", 1));
/// ```
///
/// [`Context`]: ./struct.Context.html
/// [`module`]: ./struct.Context.html#method.module
#[must_use]
pub struct Module<'a> {
    context: &'a Context<'a>,

    pub(crate) name: String,

    pub(crate) inputs: RefCell<BTreeMap<String, &'a Signal<'a>>>,
    pub(crate) outputs: RefCell<BTreeMap<String, &'a Signal<'a>>>,
    pub(crate) registers: RefCell<Vec<&'a Signal<'a>>>,
    pub(crate) instances: RefCell<Vec<&'a Instance<'a>>>,
}

impl<'a> Module<'a> {
    pub(super) fn new(context: &'a Context<'a>, name: String) -> Module<'a> {
        Module {
            context,

            name,

            inputs: RefCell::new(BTreeMap::new()),
            outputs: RefCell::new(BTreeMap::new()),
            registers: RefCell::new(Vec::new()),
            instances: RefCell::new(Vec::new()),
        }
    }

    /// Creates a [`Signal`] that represents the constant literal specified by `value` with `bit_width` bits.
    ///
    /// The bit width of the type provided by `value` doesn't need to match `bit_width`. but the value represented by `value` must fit into `bit_width` bits.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively, or if the specified `value` doesn't fit into `bit_width` bits.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let eight_bit_const = m.lit(0xffu32, 8);
    /// let one_bit_const = m.lit(0u32, 1);
    /// let twenty_seven_bit_const = m.lit(true, 27);
    /// ```
    ///
    /// [`MIN_SIGNAL_BIT_WIDTH`]: ./constant.MIN_SIGNAL_BIT_WIDTH.html
    /// [`MAX_SIGNAL_BIT_WIDTH`]: ./constant.MAX_SIGNAL_BIT_WIDTH.html
    /// [`Signal`]: ./struct.Signal.html
    pub fn lit<V: Into<Value>>(&'a self, value: V, bit_width: u32) -> &Signal<'a> {
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a literal with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a literal with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let value = value.into();
        let required_bits = value.required_bits();
        if required_bits > bit_width {
            let numeric_value = value.numeric_value();
            panic!("Cannot fit the specified value '{}' into the specified bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, bit_width, numeric_value, required_bits);
        }
        self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Lit { value, bit_width },
        })
    }

    /// Convenience method to create a [`Signal`] that represents a single `0` bit.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// // The following two signals are semantically equivalent:
    /// let low1 = m.low();
    /// let low2 = m.lit(false, 1);
    /// ```
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub fn low(&'a self) -> &Signal<'a> {
        self.lit(false, 1)
    }

    /// Convenience method to create a [`Signal`] that represents a single `1` bit.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// // The following two signals are semantically equivalent:
    /// let high1 = m.high();
    /// let high2 = m.lit(true, 1);
    /// ```
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub fn high(&'a self) -> &Signal<'a> {
        self.lit(true, 1)
    }

    /// Creates an input for this `Module` called `name` with `bit_width` bits, and returns a [`Signal`] that represents the value of this input.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_input = m.input("my_input", 80);
    /// ```
    ///
    /// [`MIN_SIGNAL_BIT_WIDTH`]: ./constant.MIN_SIGNAL_BIT_WIDTH.html
    /// [`MAX_SIGNAL_BIT_WIDTH`]: ./constant.MAX_SIGNAL_BIT_WIDTH.html
    /// [`Signal`]: ./struct.Signal.html
    pub fn input<S: Into<String>>(&'a self, name: S, bit_width: u32) -> &Signal<'a> {
        let name = name.into();
        // TODO: Error if name already exists in this context
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create an input with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create an input with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let input = self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Input {
                name: name.clone(),
                bit_width,
            },
        });
        self.inputs.borrow_mut().insert(name, input);
        input
    }

    /// Creates an output for this `Module` called `name` with the same number of bits as `source`, and drives this output with `source`.
    ///
    /// # Panics
    ///
    /// Panics of `source` doesn't belong to this `Module`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let some_signal = m.high();
    /// m.output("my_output", some_signal);
    /// ```
    pub fn output<S: Into<String>>(&'a self, name: S, source: &'a Signal<'a>) {
        if !ptr::eq(self, source.module) {
            panic!("Cannot output a signal from another module.");
        }
        // TODO: Error if name already exists in this context
        self.outputs.borrow_mut().insert(name.into(), source);
    }

    /// Creates a [`Register`] in this `Module` called `name` with `bit_width` bits.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("my_module");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32);
    /// my_reg.drive_next(!my_reg.value);
    /// m.output("my_output", my_reg.value);
    /// ```
    ///
    /// [`Register`]: ./struct.Register.html
    pub fn reg<S: Into<String>>(&'a self, name: S, bit_width: u32) -> &Register<'a> {
        // TODO: bit_width bounds checks
        // TODO: Error if name already exists in this context
        let data = self.context.register_data_arena.alloc(RegisterData {
            name: name.into(),
            initial_value: RefCell::new(None),
            bit_width,
            next: RefCell::new(None),
        });
        let value = self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Reg { data },
        });
        self.registers.borrow_mut().push(value);
        self.context.register_arena.alloc(Register { data, value })
    }

    pub fn mux(
        &'a self,
        cond: &'a Signal<'a>,
        when_true: &'a Signal<'a>,
        when_false: &'a Signal<'a>,
    ) -> &Signal<'a> {
        // TODO: This is an optimization to support kaze_sugar; if that doesn't go well, remove this
        if ptr::eq(when_true, when_false) {
            return when_true;
        }

        // TODO: Ensure when_true and when_false have the same bit widths
        // TODO: Ensure sel is 1 bit wide
        self.context.signal_arena.alloc(Signal {
            context: self.context,
            module: self,

            data: SignalData::Mux {
                cond,
                when_true,
                when_false,
            },
        })
    }

    /// Instantiates the `Module` identified by `module_name` in this [`Context`] inside this `Module` definition called `instance_name`, and returns the new [`Instance`].
    ///
    /// # Panics
    ///
    /// Panics if a `Module` identified by `module_name` doesn't exist in this [`Context`].
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// // Inner module (simple pass-through)
    /// let inner = c.module("inner");
    /// inner.output("o", inner.input("i", 32));
    ///
    /// // Outer module (wraps a single `inner` instance)
    /// let outer = c.module("outer");
    /// let inner_inst = outer.instance("inner", "inner_inst");
    /// inner_inst.drive_input("i", outer.input("i", 32));
    /// outer.output("o", inner_inst.output("o"));
    /// ```
    ///
    /// [`Context`]: ./struct.Context.html
    /// [`Instance`]: ./struct.Instance.html
    pub fn instance<S: Into<String>>(
        &'a self,
        module_name: &str,
        instance_name: S,
    ) -> &Instance<'a> {
        // TODO: Error if instance_name already exists in this context
        match self.context.modules.borrow().get(module_name) {
            Some(instantiated_module) => {
                let ret = self.context.instance_arena.alloc(Instance {
                    context: self.context,
                    module: self,

                    instantiated_module,
                    name: instance_name.into(),
                    driven_inputs: RefCell::new(BTreeMap::new()),
                });
                self.instances.borrow_mut().push(ret);
                ret
            }
            _ => panic!("Attempted to instantiate a module identified by \"{}\", but no such module exists in this context.", module_name)
        }
    }
}

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

    #[test]
    #[should_panic(
        expected = "Cannot create a literal with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn lit_bit_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(false, 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a literal with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn lit_bit_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(false, 129);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into the specified bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_1() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(128u32, 7);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into the specified bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_2() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(128u64, 2);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '1023' into the specified bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_3() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(1023u128, 4);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '65536' into the specified bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_4() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.lit(65536u32, 1);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create an input with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn input_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.input("i", 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create an input with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn input_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.input("i", 129);
    }

    #[test]
    #[should_panic(expected = "Cannot output a signal from another module.")]
    fn output_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a");

        let m2 = c.module("b");
        let i = m2.high();

        // Panic
        m1.output("a", i);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to instantiate a module identified by \"nope\", but no such module exists in this context."
    )]
    fn instantiate_nonexistent_module_error() {
        let c = Context::new();

        let m = c.module("a");

        // Panic
        let _ = m.instance("nope", "lol");
    }
}
<|endoftext|>


<commit_before>//! Diagnostic reporting support for the codespan crate.

use std::str::FromStr;
use termcolor::ColorChoice;

mod diagnostic;
mod emitter;

pub use termcolor;

pub use self::diagnostic::{Diagnostic, Label, Severity};
pub use self::emitter::{emit, Config};

/// A command line argument that configures the coloring of the output.
///
/// This can be used with command line argument parsers like `clap` or `structopt`.
///
/// # Example
///
/// ```rust
/// use structopt::StructOpt;
/// use codespan_reporting::termcolor::StandardStream;
/// use codespan_reporting::ColorArg;
///
/// #[derive(Debug, StructOpt)]
/// #[structopt(name = "groovey-app")]
/// pub struct Opts {
///     /// Configure coloring of output
///     #[structopt(
///         long = "color",
///         parse(try_from_str),
///         default_value = "auto",
///         raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
///     )]
///     pub color: ColorArg,
/// }
///
/// fn main() {
///     let opts = Opts::from_args();
///     let writer = StandardStream::stderr(opts.color.into());
/// }
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ColorArg(pub ColorChoice);

impl ColorArg {
    /// Allowed values the argument.
    ///
    /// This is useful for generating documentation via `clap` or `structopt`'s
    /// `possible_values` configuration.
    pub const VARIANTS: &'static [&'static str] = &["auto", "always", "ansi", "never"];
}

impl FromStr for ColorArg {
    type Err = &'static str;

    fn from_str(src: &str) -> Result<ColorArg, &'static str> {
        match src {
            _ if src.eq_ignore_ascii_case("auto") => Ok(ColorArg(ColorChoice::Auto)),
            _ if src.eq_ignore_ascii_case("always") => Ok(ColorArg(ColorChoice::Always)),
            _ if src.eq_ignore_ascii_case("ansi") => Ok(ColorArg(ColorChoice::AlwaysAnsi)),
            _ if src.eq_ignore_ascii_case("never") => Ok(ColorArg(ColorChoice::Never)),
            _ => Err("valid values: auto, always, ansi, never"),
        }
    }
}

impl Into<ColorChoice> for ColorArg {
    fn into(self) -> ColorChoice {
        self.0
    }
}
<commit_msg>Reexport DisplayStyle<commit_after>//! Diagnostic reporting support for the codespan crate.

use std::str::FromStr;
use termcolor::ColorChoice;

mod diagnostic;
mod emitter;

pub use termcolor;

pub use self::diagnostic::{Diagnostic, Label, Severity};
pub use self::emitter::{emit, Config, DisplayStyle};

/// A command line argument that configures the coloring of the output.
///
/// This can be used with command line argument parsers like `clap` or `structopt`.
///
/// # Example
///
/// ```rust
/// use structopt::StructOpt;
/// use codespan_reporting::termcolor::StandardStream;
/// use codespan_reporting::ColorArg;
///
/// #[derive(Debug, StructOpt)]
/// #[structopt(name = "groovey-app")]
/// pub struct Opts {
///     /// Configure coloring of output
///     #[structopt(
///         long = "color",
///         parse(try_from_str),
///         default_value = "auto",
///         raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
///     )]
///     pub color: ColorArg,
/// }
///
/// fn main() {
///     let opts = Opts::from_args();
///     let writer = StandardStream::stderr(opts.color.into());
/// }
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ColorArg(pub ColorChoice);

impl ColorArg {
    /// Allowed values the argument.
    ///
    /// This is useful for generating documentation via `clap` or `structopt`'s
    /// `possible_values` configuration.
    pub const VARIANTS: &'static [&'static str] = &["auto", "always", "ansi", "never"];
}

impl FromStr for ColorArg {
    type Err = &'static str;

    fn from_str(src: &str) -> Result<ColorArg, &'static str> {
        match src {
            _ if src.eq_ignore_ascii_case("auto") => Ok(ColorArg(ColorChoice::Auto)),
            _ if src.eq_ignore_ascii_case("always") => Ok(ColorArg(ColorChoice::Always)),
            _ if src.eq_ignore_ascii_case("ansi") => Ok(ColorArg(ColorChoice::AlwaysAnsi)),
            _ if src.eq_ignore_ascii_case("never") => Ok(ColorArg(ColorChoice::Never)),
            _ => Err("valid values: auto, always, ansi, never"),
        }
    }
}

impl Into<ColorChoice> for ColorArg {
    fn into(self) -> ColorChoice {
        self.0
    }
}
<|endoftext|>


<commit_before>//! Specialized demo of SDL for use on platforms that really want to
//! initialize and own the main routine and thread. This is meant to be
//! linked with object code compiled from one of the SDL_main variants
//! that one can find beneath <SDL-distribution>/src/main/.
//!
//! For example on Mac OS X one can build a runnable program from this
//! with something along the lines of:
//!
//!   rustc src/sdl-demo/sdl_main.rs -L. \
//!       -C link-args="-lSDLmain -lSDL -Wl,-framework,Cocoa"

#![no_main]

extern crate sdl;

use std::rand::Rng;

use sdl::video::{SurfaceFlag, VideoFlag};
use sdl::event::{Event, Key};

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn SDL_main(argc: int, argv: *const *const u8) {
    std::rt::start(argc, argv, real_main);
}

pub fn real_main() {
    sdl::init([sdl::InitFlag::Video].as_slice());
    sdl::wm::set_caption("rust-sdl demo - video", "rust-sdl");

    let mut rng = std::rand::task_rng();
    let screen = match sdl::video::set_video_mode(800, 600, 32,
                                                  [SurfaceFlag::HWSurface].as_slice(),
                                                  [VideoFlag::DoubleBuf].as_slice()) {
        Ok(screen) => screen,
        Err(err) => panic!("failed to set video mode: {}", err)
    };

    // Note: You'll want to put this and the flip call inside the main loop
    // but we don't as to not startle epileptics
    for i in range(0u, 10) {
        for j in range(0u, 10) {
            screen.fill_rect(Some(sdl::Rect {
                x: (i as i16) * 800 / 10,
                y: (j as i16) * 600 / 10,
                w: 800 / 10,
                h: 600 / 10
            }), rng.gen::<sdl::video::Color>());
        }
    }

    screen.flip();

    'main : loop {
        'event : loop {
            match sdl::event::poll_event() {
                Event::Quit => break 'main,
                Event::None => break 'event,
                Event::Key(k, _, _, _)
                    if k == Key::Escape
                        => break 'main,
                _ => {}
            }
        }
    }

    sdl::quit();
}
<commit_msg>Fix `sdl_main` demo due to librustrt -> std::rt<commit_after>//! Specialized demo of SDL for use on platforms that really want to
//! initialize and own the main routine and thread. This is meant to be
//! linked with object code compiled from one of the SDL_main variants
//! that one can find beneath <SDL-distribution>/src/main/.
//!
//! For example on Mac OS X one can build a runnable program from this
//! with something along the lines of:
//!
//!   rustc src/sdl-demo/sdl_main.rs -L. \
//!       -C link-args="-lSDLmain -lSDL -Wl,-framework,Cocoa"

#![no_main]

extern crate sdl;

use std::rand::Rng;

use sdl::video::{SurfaceFlag, VideoFlag};
use sdl::event::{Event, Key};

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn SDL_main() {
    real_main()
}

pub fn real_main() {
    sdl::init([sdl::InitFlag::Video].as_slice());
    sdl::wm::set_caption("rust-sdl demo - video", "rust-sdl");

    let mut rng = std::rand::task_rng();
    let screen = match sdl::video::set_video_mode(800, 600, 32,
                                                  [SurfaceFlag::HWSurface].as_slice(),
                                                  [VideoFlag::DoubleBuf].as_slice()) {
        Ok(screen) => screen,
        Err(err) => panic!("failed to set video mode: {}", err)
    };

    // Note: You'll want to put this and the flip call inside the main loop
    // but we don't as to not startle epileptics
    for i in range(0u, 10) {
        for j in range(0u, 10) {
            screen.fill_rect(Some(sdl::Rect {
                x: (i as i16) * 800 / 10,
                y: (j as i16) * 600 / 10,
                w: 800 / 10,
                h: 600 / 10
            }), rng.gen::<sdl::video::Color>());
        }
    }

    screen.flip();

    'main : loop {
        'event : loop {
            match sdl::event::poll_event() {
                Event::Quit => break 'main,
                Event::None => break 'event,
                Event::Key(k, _, _, _)
                    if k == Key::Escape
                        => break 'main,
                _ => {}
            }
        }
    }

    sdl::quit();
}
<|endoftext|>


<commit_before>//! Propagates scope-specific information to `into_model` transformations.

use super::naming::Naming;
use core::{Context, RpName, RpPackage, RpVersionedPackage};
use std::collections::HashMap;
use std::rc::Rc;

struct Root {
    pub ctx: Rc<Context>,
    pub package_prefix: Option<RpPackage>,
    pub package: RpVersionedPackage,
    pub prefixes: HashMap<String, RpVersionedPackage>,
    pub endpoint_naming: Option<Box<Naming>>,
    pub field_naming: Option<Box<Naming>>,
}

/// Model of a scope.
enum Inner {
    Root { root: Rc<Root> },
    Child {
        root: Rc<Root>,
        name: String,
        parent: Rc<Inner>,
    },
}

pub struct Scope {
    inner: Rc<Inner>,
}

impl Scope {
    pub fn new(
        ctx: Rc<Context>,
        package_prefix: Option<RpPackage>,
        package: RpVersionedPackage,
        prefixes: HashMap<String, RpVersionedPackage>,
        endpoint_naming: Option<Box<Naming>>,
        field_naming: Option<Box<Naming>>,
    ) -> Scope {
        let root = Rc::new(Root {
            ctx: ctx,
            package_prefix: package_prefix,
            package: package,
            prefixes: prefixes,
            endpoint_naming: endpoint_naming,
            field_naming: field_naming,
        });

        let inner_root = Inner::Root { root: root.clone() };

        Scope { inner: Rc::new(inner_root) }
    }

    /// Apply global package prefix.
    fn package_prefix(
        &self,
        package_prefix: &Option<RpPackage>,
        package: &RpVersionedPackage,
    ) -> RpVersionedPackage {
        package_prefix
            .as_ref()
            .map(|prefix| prefix.join_versioned(package))
            .unwrap_or_else(|| package.clone())
    }

    pub fn child<S: AsRef<str>>(&self, name: S) -> Scope {
        let root = match *self.inner {
            Inner::Root { ref root, .. } |
            Inner::Child { ref root, .. } => root.clone(),
        };

        Scope {
            inner: Rc::new(Inner::Child {
                root: root,
                name: name.as_ref().to_owned(),
                parent: self.inner.clone(),
            }),
        }
    }

    /// Access the error context.
    pub fn ctx(&self) -> &Context {
        match *self.inner {
            Inner::Root { ref root, .. } |
            Inner::Child { ref root, .. } => root.ctx.as_ref(),
        }
    }

    pub fn lookup_prefix(&self, prefix: &String) -> Option<&RpVersionedPackage> {
        match *self.inner {
            Inner::Root { ref root, .. } |
            Inner::Child { ref root, .. } => root.prefixes.get(prefix),
        }
    }

    pub fn package(&self) -> RpVersionedPackage {
        match *self.inner {
            Inner::Root { ref root, .. } |
            Inner::Child { ref root, .. } => {
                self.package_prefix(&root.package_prefix, &root.package)
            }
        }
    }

    pub fn walk(&self) -> ScopeWalker {
        ScopeWalker { current: self.inner.clone() }
    }

    pub fn as_name(&self) -> RpName {
        let mut parts: Vec<_> = self.walk().collect();
        parts.reverse();

        RpName {
            prefix: None,
            package: self.package(),
            parts: parts,
        }
    }

    pub fn endpoint_naming(&self) -> Option<&Naming> {
        match *self.inner {
            Inner::Root { ref root, .. } |
            Inner::Child { ref root, .. } => root.endpoint_naming.as_ref().map(AsRef::as_ref),
        }
    }

    pub fn field_naming(&self) -> Option<&Naming> {
        match *self.inner {
            Inner::Root { ref root, .. } |
            Inner::Child { ref root, .. } => root.field_naming.as_ref().map(AsRef::as_ref),
        }
    }
}

pub struct ScopeWalker {
    current: Rc<Inner>,
}

impl Iterator for ScopeWalker {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        let (next, current) = match *self.current {
            Inner::Root { .. } => {
                return None;
            }
            Inner::Child {
                ref name,
                ref parent,
                ..
            } => (Some(name.to_owned()), parent.clone()),
        };

        self.current = current;
        next
    }
}

#[cfg(test)]
mod tests {
    use super::Scope;
    use core::{RpPackage, RpVersionedPackage};
    use std::collections::HashMap;

    #[test]
    pub fn test_scope() {
        let package = RpVersionedPackage::new(RpPackage::empty(), None);
        let prefixes = HashMap::new();
        let s = Scope::new(None, package, prefixes, None, None);

        let s2 = s.child("foo");
        let s3 = s2.child("bar");

        let parts: Vec<_> = s3.walk().collect();

        assert_eq!(vec!["bar".to_owned(), "foo".to_owned()], parts);
    }
}
<commit_msg>[backend] cleanup scope<commit_after>//! Propagates scope-specific information to `into_model` transformations.

use super::naming::Naming;
use core::{Context, RpName, RpPackage, RpVersionedPackage};
use std::collections::HashMap;
use std::rc::Rc;

/// Root of the scope.
struct Root {
    ctx: Rc<Context>,
    package_prefix: Option<RpPackage>,
    package: RpVersionedPackage,
    prefixes: HashMap<String, RpVersionedPackage>,
    endpoint_naming: Option<Box<Naming>>,
    field_naming: Option<Box<Naming>>,
}

/// Model of a scope.
enum Inner {
    Root(Rc<Root>),
    Child {
        root: Rc<Root>,
        name: String,
        parent: Rc<Inner>,
    },
}

pub struct Scope(Rc<Inner>);

impl Scope {
    pub fn new(
        ctx: Rc<Context>,
        package_prefix: Option<RpPackage>,
        package: RpVersionedPackage,
        prefixes: HashMap<String, RpVersionedPackage>,
        endpoint_naming: Option<Box<Naming>>,
        field_naming: Option<Box<Naming>>,
    ) -> Scope {
        Scope(Rc::new(Inner::Root(Rc::new(Root {
            ctx: ctx,
            package_prefix: package_prefix,
            package: package,
            prefixes: prefixes,
            endpoint_naming: endpoint_naming,
            field_naming: field_naming,
        }))))
    }

    #[inline(always)]
    fn root(&self) -> &Rc<Root> {
        match *self.0 {
            Inner::Root(ref root) |
            Inner::Child { ref root, .. } => root,
        }
    }

    /// Walk the entire path of the scope.
    pub fn walk(&self) -> ScopeWalker {
        ScopeWalker { current: self.0.clone() }
    }

    /// Create a new child scope.
    pub fn child<S: AsRef<str>>(&self, name: S) -> Scope {
        Scope(Rc::new(Inner::Child {
            root: self.root().clone(),
            name: name.as_ref().to_owned(),
            parent: self.0.clone(),
        }))
    }

    /// Access the error context.
    pub fn ctx(&self) -> &Context {
        self.root().ctx.as_ref()
    }

    /// Lookup what package a given prefix belongs to.
    pub fn lookup_prefix(&self, prefix: &String) -> Option<&RpVersionedPackage> {
        self.root().prefixes.get(prefix)
    }

    /// Get the package that this scope belongs to.
    pub fn package(&self) -> RpVersionedPackage {
        let root = self.root();

        root.package_prefix
            .as_ref()
            .map(|prefix| prefix.join_versioned(&root.package))
            .unwrap_or_else(|| root.package.clone())
    }

    /// Get the current path as a name.
    pub fn as_name(&self) -> RpName {
        let mut parts: Vec<_> = self.walk().collect();
        parts.reverse();

        RpName {
            prefix: None,
            package: self.package(),
            parts: parts,
        }
    }

    /// Access active endpoint naming.
    pub fn endpoint_naming(&self) -> Option<&Naming> {
        self.root().endpoint_naming.as_ref().map(AsRef::as_ref)
    }

    /// Access active field naming.
    pub fn field_naming(&self) -> Option<&Naming> {
        self.root().field_naming.as_ref().map(AsRef::as_ref)
    }
}

/// Walker over all components of the scope.
pub struct ScopeWalker {
    current: Rc<Inner>,
}

impl Iterator for ScopeWalker {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        let (next, current) = match *self.current {
            Inner::Root(_) => {
                return None;
            }
            Inner::Child {
                ref name,
                ref parent,
                ..
            } => (Some(name.to_owned()), parent.clone()),
        };

        self.current = current;
        next
    }
}

#[cfg(test)]
mod tests {
    use super::Scope;
    use core::{RpPackage, RpVersionedPackage};
    use std::collections::HashMap;

    #[test]
    pub fn test_scope() {
        let package = RpVersionedPackage::new(RpPackage::empty(), None);
        let prefixes = HashMap::new();
        let s = Scope::new(None, package, prefixes, None, None);

        let s2 = s.child("foo");
        let s3 = s2.child("bar");

        let parts: Vec<_> = s3.walk().collect();

        assert_eq!(vec!["bar".to_owned(), "foo".to_owned()], parts);
    }
}
<|endoftext|>


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

use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::stderr;
use std::io::Write;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::{Configuration, InternalConfiguration};
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
use logger::ImagLogger;

use libimagstore::store::{Store, InMemoryFileAbstraction};
use spec::CliSpec;

/// The Runtime object
///
/// This object contains the complete runtime environment of the imag application running.
#[derive(Debug)]
pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Option<Configuration>,
    cli_matches: ArgMatches<'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /// Gets the CLI spec for the program and retreives the config file path (or uses the default on
    /// in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
    /// and builds the Runtime object with it.
    ///
    /// The cli_app object should be initially build with the ::get_default_cli_builder() function.
    pub fn new<C>(cli_app: C) -> Result<Runtime<'a>, RuntimeError>
        where C: Clone + CliSpec<'a> + InternalConfiguration
    {
        use libimagerror::trace::trace_error;
        use libimagerror::into::IntoError;

        use configuration::error::ConfigErrorKind;

        let matches = cli_app.clone().matches();

        let rtp = get_rtp_match(&matches);

        let configpath = matches.value_of(Runtime::arg_config_name())
                                .map_or_else(|| rtp.clone(), PathBuf::from);

        debug!("Config path = {:?}", configpath);

        let config = match Configuration::new(&configpath) {
            Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
                return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
            } else {
                warn!("No config file found.");
                warn!("Continuing without configuration file");
                None
            },

            Ok(mut config) => {
                if let Err(e) = config.override_config(get_override_specs(&matches)) {
                    error!("Could not apply config overrides");
                    trace_error(&e);

                    // TODO: continue question (interactive)
                }

                Some(config)
            }
        };

        Runtime::_new(cli_app, matches, config)
    }

    /// Builds the Runtime object using the given `config`.
    pub fn with_configuration<C>(cli_app: C, config: Option<Configuration>)
                                 -> Result<Runtime<'a>, RuntimeError>
        where C: Clone + CliSpec<'a> + InternalConfiguration
    {
        let matches = cli_app.clone().matches();
        Runtime::_new(cli_app, matches, config)
    }

    fn _new<C>(mut cli_app: C, matches: ArgMatches<'a>, config: Option<Configuration>)
               -> Result<Runtime<'a>, RuntimeError>
    where C: Clone + CliSpec<'a> + InternalConfiguration
    {
        use std::io::stdout;

        use clap::Shell;

        let is_debugging = matches.is_present(Runtime::arg_debugging_name());

        if cli_app.enable_logging() {
            let is_verbose = matches.is_present(Runtime::arg_verbosity_name());
            let colored    = !matches.is_present(Runtime::arg_no_color_output_name());

            Runtime::init_logger(is_debugging, is_verbose, colored);
        }

        match matches.value_of(Runtime::arg_generate_compl()) {
            Some(shell) => {
                debug!("Generating shell completion script, writing to stdout");
                let shell   = shell.parse::<Shell>().unwrap(); // clap has our back here.
                let appname = String::from(cli_app.name());
                cli_app.completions(appname, shell, &mut stdout());
            },
            _ => debug!("Not generating shell completion script"),
        }

        let rtp = get_rtp_match(&matches);

        let storepath = matches.value_of(Runtime::arg_storepath_name())
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        debug!("RTP path    = {:?}", rtp);
        debug!("Store path  = {:?}", storepath);

        let store_config = match config {
            Some(ref c) => c.store_config().cloned(),
            None        => None,
        };

        if is_debugging {
            write!(stderr(), "Config: {:?}\n", config).ok();
            write!(stderr(), "Store-config: {:?}\n", store_config).ok();
        }

        let store_result = if cli_app.use_inmemory_fs() {
            Store::new_with_backend(storepath,
                                    store_config,
                                    Box::new(InMemoryFileAbstraction::new()))
        } else {
            Store::new(storepath, store_config)
        };

        store_result.map(|store| {
            Runtime {
                cli_matches: matches,
                configuration: config,
                rtp: rtp,
                store: store,
            }
        })
        .map_err_into(RuntimeErrorKind::Instantiate)
    }

    ///
    /// Get a commandline-interface builder object from `clap`
    ///
    /// This commandline interface builder object already contains some predefined interface flags:
    ///   * -v | --verbose for verbosity
    ///   * --debug for debugging
    ///   * -c <file> | --config <file> for alternative configuration file
    ///   * -r <path> | --rtp <path> for alternative runtimepath
    ///   * --store <path> for alternative store path
    /// Each has the appropriate help text included.
    ///
    /// The `appname` shall be "imag-<command>".
    ///
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name(Runtime::arg_verbosity_name())
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_debugging_name())
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_no_color_output_name())
                .long("no-color")
                .help("Disable color output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_config_name())
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_config_override_name())
                 .long("override-config")
                 .help("Override a configuration settings. Use 'key=value' pairs, where the key is a path in the TOML configuration. The value must be present in the configuration and be convertible to the type of the configuration setting. If the argument does not contain a '=', it gets ignored. Setting Arrays and Tables is not yet supported.")
                 .required(false)
                 .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_runtimepath_name())
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_storepath_name())
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_editor_name())
                .long("editor")
                .help("Set editor")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_generate_compl())
                .long("generate-commandline-completion")
                .help("Generate the commandline completion for bash or zsh or fish")
                .required(false)
                .takes_value(true)
                .value_name("SHELL")
                .possible_values(&["bash", "fish", "zsh"]))

    }

    /// Get the argument names of the Runtime which are available
    pub fn arg_names() -> Vec<&'static str> {
        vec![
            Runtime::arg_verbosity_name(),
            Runtime::arg_debugging_name(),
            Runtime::arg_no_color_output_name(),
            Runtime::arg_config_name(),
            Runtime::arg_config_override_name(),
            Runtime::arg_runtimepath_name(),
            Runtime::arg_storepath_name(),
            Runtime::arg_editor_name(),
        ]
    }

    /// Get the verbosity argument name for the Runtime
    pub fn arg_verbosity_name() -> &'static str {
        "verbosity"
    }

    /// Get the debugging argument name for the Runtime
    pub fn arg_debugging_name() -> &'static str {
        "debugging"
    }

    /// Get the argument name for no color output of the Runtime
    pub fn arg_no_color_output_name() -> &'static str {
        "no-color-output"
    }

    /// Get the config argument name for the Runtime
    pub fn arg_config_name() -> &'static str {
        "config"
    }

    /// Get the config-override argument name for the Runtime
    pub fn arg_config_override_name() -> &'static str {
        "config-override"
    }

    /// Get the runtime argument name for the Runtime
    pub fn arg_runtimepath_name() -> &'static str {
        "runtimepath"
    }

    /// Get the storepath argument name for the Runtime
    pub fn arg_storepath_name() -> &'static str {
        "storepath"
    }

    /// Get the editor argument name for the Runtime
    pub fn arg_editor_name() -> &'static str {
        "editor"
    }

    /// Get the argument name for generating the completion
    pub fn arg_generate_compl() -> &'static str {
        "generate-completion"
    }

    /// Initialize the internal logger
    fn init_logger(is_debugging: bool, is_verbose: bool, colored: bool) {
        use std::env::var as env_var;
        use env_logger;

        if env_var("IMAG_LOG_ENV").is_ok() {
            env_logger::init().unwrap();
        } else {
            let lvl = if is_debugging {
                LogLevelFilter::Debug
            } else if is_verbose {
                LogLevelFilter::Info
            } else {
                LogLevelFilter::Warn
            };

            log::set_logger(|max_log_lvl| {
                max_log_lvl.set(lvl);
                debug!("Init logger with {}", lvl);
                Box::new(ImagLogger::new(lvl.to_log_level().unwrap()).with_color(colored))
            })
            .map_err(|e| panic!("Could not setup logger: {:?}", e))
            .ok();
        }
    }

    /// Get the verbosity flag value
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /// Get the debugging flag value
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /// Get the runtimepath
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /// Get the commandline interface matches
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /// Get the configuration object
    pub fn config(&self) -> Option<&Configuration> {
        self.configuration.as_ref()
    }

    /// Get the store object
    pub fn store(&self) -> &Store {
        &self.store
    }

    /// Change the store backend to stdout
    ///
    /// For the documentation on purpose and cavecats, have a look at the documentation of the
    /// `Store::reset_backend()` function.
    ///
    pub fn store_backend_to_stdio(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::*;
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use std::rc::Rc;
        use std::cell::RefCell;

        let mut input = ::std::io::stdin();
        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdIoFileAbstraction::new(&mut input, output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    pub fn store_backend_to_stdout(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use libimagstore::file_abstraction::stdio::out::StdoutFileAbstraction;
        use std::rc::Rc;
        use std::cell::RefCell;

        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdoutFileAbstraction::new(output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    /// Get a editor command object which can be called to open the $EDITOR
    pub fn editor(&self) -> Option<Command> {
        self.cli()
            .value_of("editor")
            .map(String::from)
            .or(match self.configuration {
                Some(ref c) => c.editor().cloned(),
                _ => None,
            })
            .or(env::var("EDITOR").ok())
            .map(Command::new)
    }
}

fn get_rtp_match<'a>(matches: &ArgMatches<'a>) -> PathBuf {
    use std::env;

    matches.value_of(Runtime::arg_runtimepath_name())
        .map_or_else(|| {
            env::var("HOME")
                .map(PathBuf::from)
                .map(|mut p| { p.push(".imag"); p })
                .unwrap_or_else(|_| {
                    panic!("You seem to be $HOME-less. Please get a $HOME before using this \
                            software. We are sorry for you and hope you have some \
                            accommodation anyways.");
                })
        }, PathBuf::from)
}

fn get_override_specs(matches: &ArgMatches) -> Vec<String> {
    matches
        .values_of("config-override")
        .map(|values| {
             values
             .filter(|s| {
                 let b = s.contains("=");
                 if !b { warn!("override '{}' does not contain '=' - will be ignored!", s); }
                 b
             })
             .map(String::from)
             .collect()
        })
        .unwrap_or(vec![])
}

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

use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::stderr;
use std::io::Write;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::{Configuration, InternalConfiguration};
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
use logger::ImagLogger;

use libimagstore::store::Store;
use libimagstore::file_abstraction::InMemoryFileAbstraction;
use spec::CliSpec;

/// The Runtime object
///
/// This object contains the complete runtime environment of the imag application running.
#[derive(Debug)]
pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Option<Configuration>,
    cli_matches: ArgMatches<'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /// Gets the CLI spec for the program and retreives the config file path (or uses the default on
    /// in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
    /// and builds the Runtime object with it.
    ///
    /// The cli_app object should be initially build with the ::get_default_cli_builder() function.
    pub fn new<C>(cli_app: C) -> Result<Runtime<'a>, RuntimeError>
        where C: Clone + CliSpec<'a> + InternalConfiguration
    {
        use libimagerror::trace::trace_error;
        use libimagerror::into::IntoError;

        use configuration::error::ConfigErrorKind;

        let matches = cli_app.clone().matches();

        let rtp = get_rtp_match(&matches);

        let configpath = matches.value_of(Runtime::arg_config_name())
                                .map_or_else(|| rtp.clone(), PathBuf::from);

        debug!("Config path = {:?}", configpath);

        let config = match Configuration::new(&configpath) {
            Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
                return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
            } else {
                warn!("No config file found.");
                warn!("Continuing without configuration file");
                None
            },

            Ok(mut config) => {
                if let Err(e) = config.override_config(get_override_specs(&matches)) {
                    error!("Could not apply config overrides");
                    trace_error(&e);

                    // TODO: continue question (interactive)
                }

                Some(config)
            }
        };

        Runtime::_new(cli_app, matches, config)
    }

    /// Builds the Runtime object using the given `config`.
    pub fn with_configuration<C>(cli_app: C, config: Option<Configuration>)
                                 -> Result<Runtime<'a>, RuntimeError>
        where C: Clone + CliSpec<'a> + InternalConfiguration
    {
        let matches = cli_app.clone().matches();
        Runtime::_new(cli_app, matches, config)
    }

    fn _new<C>(mut cli_app: C, matches: ArgMatches<'a>, config: Option<Configuration>)
               -> Result<Runtime<'a>, RuntimeError>
    where C: Clone + CliSpec<'a> + InternalConfiguration
    {
        use std::io::stdout;

        use clap::Shell;

        let is_debugging = matches.is_present(Runtime::arg_debugging_name());

        if cli_app.enable_logging() {
            let is_verbose = matches.is_present(Runtime::arg_verbosity_name());
            let colored    = !matches.is_present(Runtime::arg_no_color_output_name());

            Runtime::init_logger(is_debugging, is_verbose, colored);
        }

        match matches.value_of(Runtime::arg_generate_compl()) {
            Some(shell) => {
                debug!("Generating shell completion script, writing to stdout");
                let shell   = shell.parse::<Shell>().unwrap(); // clap has our back here.
                let appname = String::from(cli_app.name());
                cli_app.completions(appname, shell, &mut stdout());
            },
            _ => debug!("Not generating shell completion script"),
        }

        let rtp = get_rtp_match(&matches);

        let storepath = matches.value_of(Runtime::arg_storepath_name())
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        debug!("RTP path    = {:?}", rtp);
        debug!("Store path  = {:?}", storepath);

        let store_config = match config {
            Some(ref c) => c.store_config().cloned(),
            None        => None,
        };

        if is_debugging {
            write!(stderr(), "Config: {:?}\n", config).ok();
            write!(stderr(), "Store-config: {:?}\n", store_config).ok();
        }

        let store_result = if cli_app.use_inmemory_fs() {
            Store::new_with_backend(storepath,
                                    store_config,
                                    Box::new(InMemoryFileAbstraction::new()))
        } else {
            Store::new(storepath, store_config)
        };

        store_result.map(|store| {
            Runtime {
                cli_matches: matches,
                configuration: config,
                rtp: rtp,
                store: store,
            }
        })
        .map_err_into(RuntimeErrorKind::Instantiate)
    }

    ///
    /// Get a commandline-interface builder object from `clap`
    ///
    /// This commandline interface builder object already contains some predefined interface flags:
    ///   * -v | --verbose for verbosity
    ///   * --debug for debugging
    ///   * -c <file> | --config <file> for alternative configuration file
    ///   * -r <path> | --rtp <path> for alternative runtimepath
    ///   * --store <path> for alternative store path
    /// Each has the appropriate help text included.
    ///
    /// The `appname` shall be "imag-<command>".
    ///
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name(Runtime::arg_verbosity_name())
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_debugging_name())
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_no_color_output_name())
                .long("no-color")
                .help("Disable color output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_config_name())
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_config_override_name())
                 .long("override-config")
                 .help("Override a configuration settings. Use 'key=value' pairs, where the key is a path in the TOML configuration. The value must be present in the configuration and be convertible to the type of the configuration setting. If the argument does not contain a '=', it gets ignored. Setting Arrays and Tables is not yet supported.")
                 .required(false)
                 .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_runtimepath_name())
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_storepath_name())
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_editor_name())
                .long("editor")
                .help("Set editor")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_generate_compl())
                .long("generate-commandline-completion")
                .help("Generate the commandline completion for bash or zsh or fish")
                .required(false)
                .takes_value(true)
                .value_name("SHELL")
                .possible_values(&["bash", "fish", "zsh"]))

    }

    /// Get the argument names of the Runtime which are available
    pub fn arg_names() -> Vec<&'static str> {
        vec![
            Runtime::arg_verbosity_name(),
            Runtime::arg_debugging_name(),
            Runtime::arg_no_color_output_name(),
            Runtime::arg_config_name(),
            Runtime::arg_config_override_name(),
            Runtime::arg_runtimepath_name(),
            Runtime::arg_storepath_name(),
            Runtime::arg_editor_name(),
        ]
    }

    /// Get the verbosity argument name for the Runtime
    pub fn arg_verbosity_name() -> &'static str {
        "verbosity"
    }

    /// Get the debugging argument name for the Runtime
    pub fn arg_debugging_name() -> &'static str {
        "debugging"
    }

    /// Get the argument name for no color output of the Runtime
    pub fn arg_no_color_output_name() -> &'static str {
        "no-color-output"
    }

    /// Get the config argument name for the Runtime
    pub fn arg_config_name() -> &'static str {
        "config"
    }

    /// Get the config-override argument name for the Runtime
    pub fn arg_config_override_name() -> &'static str {
        "config-override"
    }

    /// Get the runtime argument name for the Runtime
    pub fn arg_runtimepath_name() -> &'static str {
        "runtimepath"
    }

    /// Get the storepath argument name for the Runtime
    pub fn arg_storepath_name() -> &'static str {
        "storepath"
    }

    /// Get the editor argument name for the Runtime
    pub fn arg_editor_name() -> &'static str {
        "editor"
    }

    /// Get the argument name for generating the completion
    pub fn arg_generate_compl() -> &'static str {
        "generate-completion"
    }

    /// Initialize the internal logger
    fn init_logger(is_debugging: bool, is_verbose: bool, colored: bool) {
        use std::env::var as env_var;
        use env_logger;

        if env_var("IMAG_LOG_ENV").is_ok() {
            env_logger::init().unwrap();
        } else {
            let lvl = if is_debugging {
                LogLevelFilter::Debug
            } else if is_verbose {
                LogLevelFilter::Info
            } else {
                LogLevelFilter::Warn
            };

            log::set_logger(|max_log_lvl| {
                max_log_lvl.set(lvl);
                debug!("Init logger with {}", lvl);
                Box::new(ImagLogger::new(lvl.to_log_level().unwrap()).with_color(colored))
            })
            .map_err(|e| panic!("Could not setup logger: {:?}", e))
            .ok();
        }
    }

    /// Get the verbosity flag value
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /// Get the debugging flag value
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /// Get the runtimepath
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /// Get the commandline interface matches
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /// Get the configuration object
    pub fn config(&self) -> Option<&Configuration> {
        self.configuration.as_ref()
    }

    /// Get the store object
    pub fn store(&self) -> &Store {
        &self.store
    }

    /// Change the store backend to stdout
    ///
    /// For the documentation on purpose and cavecats, have a look at the documentation of the
    /// `Store::reset_backend()` function.
    ///
    pub fn store_backend_to_stdio(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::*;
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use std::rc::Rc;
        use std::cell::RefCell;

        let mut input = ::std::io::stdin();
        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdIoFileAbstraction::new(&mut input, output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    pub fn store_backend_to_stdout(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use libimagstore::file_abstraction::stdio::out::StdoutFileAbstraction;
        use std::rc::Rc;
        use std::cell::RefCell;

        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdoutFileAbstraction::new(output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    /// Get a editor command object which can be called to open the $EDITOR
    pub fn editor(&self) -> Option<Command> {
        self.cli()
            .value_of("editor")
            .map(String::from)
            .or(match self.configuration {
                Some(ref c) => c.editor().cloned(),
                _ => None,
            })
            .or(env::var("EDITOR").ok())
            .map(Command::new)
    }
}

fn get_rtp_match<'a>(matches: &ArgMatches<'a>) -> PathBuf {
    use std::env;

    matches.value_of(Runtime::arg_runtimepath_name())
        .map_or_else(|| {
            env::var("HOME")
                .map(PathBuf::from)
                .map(|mut p| { p.push(".imag"); p })
                .unwrap_or_else(|_| {
                    panic!("You seem to be $HOME-less. Please get a $HOME before using this \
                            software. We are sorry for you and hope you have some \
                            accommodation anyways.");
                })
        }, PathBuf::from)
}

fn get_override_specs(matches: &ArgMatches) -> Vec<String> {
    matches
        .values_of("config-override")
        .map(|values| {
             values
             .filter(|s| {
                 let b = s.contains("=");
                 if !b { warn!("override '{}' does not contain '=' - will be ignored!", s); }
                 b
             })
             .map(String::from)
             .collect()
        })
        .unwrap_or(vec![])
}

<|endoftext|>