<commit_before>use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};

// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
declare_clippy_lint! {
    /// ### What it does
    /// Checks for `set_len()` call that creates `Vec` with uninitialized elements.
    /// This is commonly caused by calling `set_len()` right after after calling
    /// `with_capacity()` or `reserve()`.
    ///
    /// ### Why is this bad?
    /// It creates a `Vec` with uninitialized data, which leads to
    /// undefined behavior with most safe operations.
    ///
    /// Notably, uninitialized `Vec<u8>` must not be used with generic `Read`.
    ///
    /// ### Known Problems
    /// This lint only checks directly adjacent statements.
    ///
    /// ### Example
    /// ```rust,ignore
    /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
    /// unsafe { vec.set_len(1000); }
    /// reader.read(&mut vec); // undefined behavior!
    /// ```
    ///
    /// ### How to fix?
    /// 1. Use an initialized buffer:
    ///    ```rust,ignore
    ///    let mut vec: Vec<u8> = vec![0; 1000];
    ///    reader.read(&mut vec);
    ///    ```
    /// 2. Wrap the content in `MaybeUninit`:
    ///    ```rust,ignore
    ///    let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
    ///    vec.set_len(1000);  // `MaybeUninit` can be uninitialized
    ///    ```
    /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
    ///    ```rust,ignore
    ///    let mut vec: Vec<u8> = Vec::with_capacity(1000);
    ///    let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`
    ///    // perform initialization with `remaining`
    ///    vec.set_len(...);  // Safe to call `set_len()` on initialized part
    ///    ```
    pub UNINIT_VEC,
    correctness,
    "Vec with uninitialized data"
}

declare_lint_pass!(UninitVec => [UNINIT_VEC]);

// FIXME: update to a visitor-based implementation.
// Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
impl<'tcx> LateLintPass<'tcx> for UninitVec {
    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
        if !in_external_macro(cx.tcx.sess, block.span) {
            for w in block.stmts.windows(2) {
                if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
                    handle_uninit_vec_pair(cx, &w[0], expr);
                }
            }

            if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
                handle_uninit_vec_pair(cx, stmt, expr);
            }
        }
    }
}

fn handle_uninit_vec_pair(
    cx: &LateContext<'tcx>,
    maybe_init_or_reserve: &'tcx Stmt<'tcx>,
    maybe_set_len: &'tcx Expr<'tcx>,
) {
    if_chain! {
        if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve);
        if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
        if vec.location.eq_expr(cx, set_len_self);
        if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
        if let ty::Adt(_, substs) = vec_ty.kind();
        // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
        if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
        then {
            if vec.has_capacity() {
                // with_capacity / reserve -> set_len

                // Check T of Vec<T>
                if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
                    // FIXME: #7698, false positive of the internal lints
                    #[allow(clippy::collapsible_span_lint_calls)]
                    span_lint_and_then(
                        cx,
                        UNINIT_VEC,
                        vec![call_span, maybe_init_or_reserve.span],
                        "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
                        |diag| {
                            diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
                        },
                    );
                }
            } else {
                // new / default -> set_len
                span_lint(
                    cx,
                    UNINIT_VEC,
                    vec![call_span, maybe_init_or_reserve.span],
                    "calling `set_len()` on empty `Vec` creates out-of-bound values",
                );
            }
        }
    }
}

/// The target `Vec` that is initialized or reserved
#[derive(Clone, Copy)]
struct TargetVec<'tcx> {
    location: VecLocation<'tcx>,
    /// `None` if `reserve()`
    init_kind: Option<VecInitKind>,
}

impl TargetVec<'_> {
    pub fn has_capacity(self) -> bool {
        !matches!(self.init_kind, Some(VecInitKind::New | VecInitKind::Default))
    }
}

#[derive(Clone, Copy)]
enum VecLocation<'tcx> {
    Local(HirId),
    Expr(&'tcx Expr<'tcx>),
}

impl<'tcx> VecLocation<'tcx> {
    pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
        match self {
            VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id),
            VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
        }
    }
}

/// Finds the target location where the result of `Vec` initialization is stored
/// or `self` expression for `Vec::reserve()`.
fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
    match stmt.kind {
        StmtKind::Local(local) => {
            if_chain! {
                if let Some(init_expr) = local.init;
                if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
                if let Some(init_kind) = get_vec_init_kind(cx, init_expr);
                then {
                    return Some(TargetVec {
                        location: VecLocation::Local(hir_id),
                        init_kind: Some(init_kind),
                    })
                }
            }
        },
        StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
            ExprKind::Assign(lhs, rhs, _span) => {
                if let Some(init_kind) = get_vec_init_kind(cx, rhs) {
                    return Some(TargetVec {
                        location: VecLocation::Expr(lhs),
                        init_kind: Some(init_kind),
                    });
                }
            },
            ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
                return Some(TargetVec {
                    location: VecLocation::Expr(self_expr),
                    init_kind: None,
                });
            },
            _ => (),
        },
        StmtKind::Item(_) => (),
    }
    None
}

fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
        && path.ident.name.as_str() == "reserve"
}

/// Returns self if the expression is `Vec::set_len()`
fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
    // peel unsafe blocks in `unsafe { vec.set_len() }`
    let expr = peel_hir_expr_while(expr, |e| {
        if let ExprKind::Block(block, _) = e.kind {
            // Extract the first statement/expression
            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
                (None, Some(expr)) => Some(expr),
                (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
                _ => None,
            }
        } else {
            None
        }
    });
    match expr.kind {
        ExprKind::MethodCall(path, _, [self_expr, _], _) => {
            let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
            if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
                Some((self_expr, expr.span))
            } else {
                None
            }
        },
        _ => None,
    }
}
<commit_msg>Update lint description for new() and default()<commit_after>use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};

// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
declare_clippy_lint! {
    /// ### What it does
    /// Checks for `set_len()` call that creates `Vec` with uninitialized elements.
    /// This is commonly caused by calling `set_len()` right after allocating or
    /// reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
    ///
    /// ### Why is this bad?
    /// It creates a `Vec` with uninitialized data, which leads to
    /// undefined behavior with most safe operations. Notably, uninitialized
    /// `Vec<u8>` must not be used with generic `Read`.
    ///
    /// Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
    /// creates out-of-bound values that lead to heap memory corruption when used.
    ///
    /// ### Known Problems
    /// This lint only checks directly adjacent statements.
    ///
    /// ### Example
    /// ```rust,ignore
    /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
    /// unsafe { vec.set_len(1000); }
    /// reader.read(&mut vec); // undefined behavior!
    /// ```
    ///
    /// ### How to fix?
    /// 1. Use an initialized buffer:
    ///    ```rust,ignore
    ///    let mut vec: Vec<u8> = vec![0; 1000];
    ///    reader.read(&mut vec);
    ///    ```
    /// 2. Wrap the content in `MaybeUninit`:
    ///    ```rust,ignore
    ///    let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
    ///    vec.set_len(1000);  // `MaybeUninit` can be uninitialized
    ///    ```
    /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
    ///    ```rust,ignore
    ///    let mut vec: Vec<u8> = Vec::with_capacity(1000);
    ///    let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`
    ///    // perform initialization with `remaining`
    ///    vec.set_len(...);  // Safe to call `set_len()` on initialized part
    ///    ```
    pub UNINIT_VEC,
    correctness,
    "Vec with uninitialized data"
}

declare_lint_pass!(UninitVec => [UNINIT_VEC]);

// FIXME: update to a visitor-based implementation.
// Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
impl<'tcx> LateLintPass<'tcx> for UninitVec {
    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
        if !in_external_macro(cx.tcx.sess, block.span) {
            for w in block.stmts.windows(2) {
                if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
                    handle_uninit_vec_pair(cx, &w[0], expr);
                }
            }

            if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
                handle_uninit_vec_pair(cx, stmt, expr);
            }
        }
    }
}

fn handle_uninit_vec_pair(
    cx: &LateContext<'tcx>,
    maybe_init_or_reserve: &'tcx Stmt<'tcx>,
    maybe_set_len: &'tcx Expr<'tcx>,
) {
    if_chain! {
        if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve);
        if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
        if vec.location.eq_expr(cx, set_len_self);
        if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
        if let ty::Adt(_, substs) = vec_ty.kind();
        // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
        if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
        then {
            if vec.has_capacity() {
                // with_capacity / reserve -> set_len

                // Check T of Vec<T>
                if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
                    // FIXME: #7698, false positive of the internal lints
                    #[allow(clippy::collapsible_span_lint_calls)]
                    span_lint_and_then(
                        cx,
                        UNINIT_VEC,
                        vec![call_span, maybe_init_or_reserve.span],
                        "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
                        |diag| {
                            diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
                        },
                    );
                }
            } else {
                // new / default -> set_len
                span_lint(
                    cx,
                    UNINIT_VEC,
                    vec![call_span, maybe_init_or_reserve.span],
                    "calling `set_len()` on empty `Vec` creates out-of-bound values",
                );
            }
        }
    }
}

/// The target `Vec` that is initialized or reserved
#[derive(Clone, Copy)]
struct TargetVec<'tcx> {
    location: VecLocation<'tcx>,
    /// `None` if `reserve()`
    init_kind: Option<VecInitKind>,
}

impl TargetVec<'_> {
    pub fn has_capacity(self) -> bool {
        !matches!(self.init_kind, Some(VecInitKind::New | VecInitKind::Default))
    }
}

#[derive(Clone, Copy)]
enum VecLocation<'tcx> {
    Local(HirId),
    Expr(&'tcx Expr<'tcx>),
}

impl<'tcx> VecLocation<'tcx> {
    pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
        match self {
            VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id),
            VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
        }
    }
}

/// Finds the target location where the result of `Vec` initialization is stored
/// or `self` expression for `Vec::reserve()`.
fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
    match stmt.kind {
        StmtKind::Local(local) => {
            if_chain! {
                if let Some(init_expr) = local.init;
                if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
                if let Some(init_kind) = get_vec_init_kind(cx, init_expr);
                then {
                    return Some(TargetVec {
                        location: VecLocation::Local(hir_id),
                        init_kind: Some(init_kind),
                    })
                }
            }
        },
        StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
            ExprKind::Assign(lhs, rhs, _span) => {
                if let Some(init_kind) = get_vec_init_kind(cx, rhs) {
                    return Some(TargetVec {
                        location: VecLocation::Expr(lhs),
                        init_kind: Some(init_kind),
                    });
                }
            },
            ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
                return Some(TargetVec {
                    location: VecLocation::Expr(self_expr),
                    init_kind: None,
                });
            },
            _ => (),
        },
        StmtKind::Item(_) => (),
    }
    None
}

fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
        && path.ident.name.as_str() == "reserve"
}

/// Returns self if the expression is `Vec::set_len()`
fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
    // peel unsafe blocks in `unsafe { vec.set_len() }`
    let expr = peel_hir_expr_while(expr, |e| {
        if let ExprKind::Block(block, _) = e.kind {
            // Extract the first statement/expression
            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
                (None, Some(expr)) => Some(expr),
                (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
                _ => None,
            }
        } else {
            None
        }
    });
    match expr.kind {
        ExprKind::MethodCall(path, _, [self_expr, _], _) => {
            let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
            if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
                Some((self_expr, expr.span))
            } else {
                None
            }
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Evcxr Authors.
//
// 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
//
//     https://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 anyhow::anyhow;
use anyhow::bail;
use anyhow::Result;
use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

const LOGO_32X32: &[u8] = include_bytes!("../third_party/rust/rust-logo-32x32.png");
const LOGO_64X64: &[u8] = include_bytes!("../third_party/rust/rust-logo-64x64.png");
const LOGO_LICENSE: &[u8] = include_bytes!("../third_party/rust/LICENSE.md");
const KERNEL_JS: &[u8] = include_bytes!("../client/kernel.js");
const LINT_JS: &[u8] = include_bytes!("../third_party/CodeMirror/addons/lint/lint.js");
const LINT_CSS: &[u8] = include_bytes!("../third_party/CodeMirror/addons/lint/lint.css");
const LINT_LICENSE: &[u8] = include_bytes!("../third_party/CodeMirror/LICENSE");
const VERSION_TXT: &[u8] = include_bytes!("../client/version.txt");

pub(crate) fn install() -> Result<()> {
    let kernel_dir = get_kernel_dir()?;
    fs::create_dir_all(&kernel_dir)?;
    let current_exe_path = env::current_exe()?;
    let current_exe = current_exe_path
        .to_str()
        .ok_or_else(|| anyhow!("current exe path isn't valid UTF-8"))?;
    let kernel_json = object! {
        "argv" => array![current_exe, "--control_file", "{connection_file}"],
        "display_name" => "Rust",
        "language" => "rust",
        "interrupt_mode" => "message",
    };
    let kernel_json_filename = kernel_dir.join("kernel.json");
    println!("Writing {}", kernel_json_filename.to_string_lossy());
    kernel_json.write_pretty(&mut fs::File::create(kernel_json_filename)?, 2)?;
    install_resource(&kernel_dir, "logo-32x32.png", LOGO_32X32)?;
    install_resource(&kernel_dir, "logo-64x64.png", LOGO_64X64)?;
    install_resource(&kernel_dir, "logo-LICENSE.md", LOGO_LICENSE)?;
    install_resource(&kernel_dir, "kernel.js", KERNEL_JS)?;
    install_resource(&kernel_dir, "lint.js", LINT_JS)?;
    install_resource(&kernel_dir, "lint.css", LINT_CSS)?;
    install_resource(&kernel_dir, "lint-LICENSE", LINT_LICENSE)?;
    install_resource(&kernel_dir, "version.txt", VERSION_TXT)?;
    println!("Installation complete");
    Ok(())
}

/// Checks if the current installation is out-of-date, by looking at what's in
/// version.txt. If it is out of date, then updates it.
pub(crate) fn update_if_necessary() -> Result<()> {
    let kernel_dir = get_kernel_dir()?;
    let installed_version = std::fs::read(kernel_dir.join("version.txt")).unwrap_or_default();
    if installed_version != VERSION_TXT {
        install()?;
        eprintln!(
            "\n\n==================================================================\n\
            Updated Evcxr Jupyter installation. Note, updates unfortunately \n\
            won't take effect until the next time you start jupyter notebook.\n\
            ==================================================================\n"
        );
    }
    Ok(())
}

pub(crate) fn install_resource(dir: &Path, filename: &str, bytes: &'static [u8]) -> Result<()> {
    let res_path = dir.join(filename);
    println!("Writing {}", res_path.to_string_lossy());
    let mut file = fs::File::create(res_path)?;
    file.write_all(bytes)?;
    Ok(())
}

pub(crate) fn uninstall() -> Result<()> {
    let kernel_dir = get_kernel_dir()?;
    println!("Deleting {}", kernel_dir.to_string_lossy());
    fs::remove_dir_all(kernel_dir)?;
    println!("Uninstall complete");
    Ok(())
}

// https://jupyter-client.readthedocs.io/en/latest/kernels.html
fn get_kernel_dir() -> Result<PathBuf> {
    let jupyter_dir = if let Ok(dir) = env::var("JUPYTER_PATH") {
        PathBuf::from(dir)
    } else if let Some(dir) = get_user_kernel_dir() {
        dir
    } else {
        bail!("Couldn't get XDG data directory");
    };
    Ok(jupyter_dir.join("kernels").join("rust"))
}

#[cfg(not(target_os = "macos"))]
fn get_user_kernel_dir() -> Option<PathBuf> {
    dirs::data_dir().map(|data_dir| data_dir.join("jupyter"))
}

#[cfg(target_os = "macos")]
fn get_user_kernel_dir() -> Option<PathBuf> {
    dirs::data_dir().and_then(|d| d.parent().map(|data_dir| data_dir.join("Jupyter")))
}
<commit_msg>evcxr_jupyter: Don't update kernel.json if it wasn't already installed<commit_after>// Copyright 2020 The Evcxr Authors.
//
// 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
//
//     https://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 anyhow::anyhow;
use anyhow::bail;
use anyhow::Result;
use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;

const LOGO_32X32: &[u8] = include_bytes!("../third_party/rust/rust-logo-32x32.png");
const LOGO_64X64: &[u8] = include_bytes!("../third_party/rust/rust-logo-64x64.png");
const LOGO_LICENSE: &[u8] = include_bytes!("../third_party/rust/LICENSE.md");
const KERNEL_JS: &[u8] = include_bytes!("../client/kernel.js");
const LINT_JS: &[u8] = include_bytes!("../third_party/CodeMirror/addons/lint/lint.js");
const LINT_CSS: &[u8] = include_bytes!("../third_party/CodeMirror/addons/lint/lint.css");
const LINT_LICENSE: &[u8] = include_bytes!("../third_party/CodeMirror/LICENSE");
const VERSION_TXT: &[u8] = include_bytes!("../client/version.txt");

pub(crate) fn install() -> Result<()> {
    let kernel_dir = get_kernel_dir()?;
    fs::create_dir_all(&kernel_dir)?;
    let current_exe_path = env::current_exe()?;
    let current_exe = current_exe_path
        .to_str()
        .ok_or_else(|| anyhow!("current exe path isn't valid UTF-8"))?;
    let kernel_json = object! {
        "argv" => array![current_exe, "--control_file", "{connection_file}"],
        "display_name" => "Rust",
        "language" => "rust",
        "interrupt_mode" => "message",
    };
    let kernel_json_filename = kernel_dir.join("kernel.json");
    println!("Writing {}", kernel_json_filename.to_string_lossy());
    kernel_json.write_pretty(&mut fs::File::create(kernel_json_filename)?, 2)?;
    install_resource(&kernel_dir, "logo-32x32.png", LOGO_32X32)?;
    install_resource(&kernel_dir, "logo-64x64.png", LOGO_64X64)?;
    install_resource(&kernel_dir, "logo-LICENSE.md", LOGO_LICENSE)?;
    install_resource(&kernel_dir, "kernel.js", KERNEL_JS)?;
    install_resource(&kernel_dir, "lint.js", LINT_JS)?;
    install_resource(&kernel_dir, "lint.css", LINT_CSS)?;
    install_resource(&kernel_dir, "lint-LICENSE", LINT_LICENSE)?;
    install_resource(&kernel_dir, "version.txt", VERSION_TXT)?;
    println!("Installation complete");
    Ok(())
}

/// Checks if the current installation is out-of-date, by looking at what's in
/// version.txt. If it is out of date, then updates it.
pub(crate) fn update_if_necessary() -> Result<()> {
    let kernel_dir = get_kernel_dir()?;
    // If the kernel directory doesn't exist, then we're probably being run from
    // a wrapper, so we shouldn't "update", since that would in effect be
    // installing ourselves when we weren't already installed.
    if !kernel_dir.exists() {
        return Ok(());
    }
    let installed_version = std::fs::read(kernel_dir.join("version.txt")).unwrap_or_default();
    if installed_version != VERSION_TXT {
        install()?;
        eprintln!(
            "\n\n==================================================================\n\
            Updated Evcxr Jupyter installation. Note, updates unfortunately \n\
            won't take effect until the next time you start jupyter notebook.\n\
            ==================================================================\n"
        );
    }
    Ok(())
}

pub(crate) fn install_resource(dir: &Path, filename: &str, bytes: &'static [u8]) -> Result<()> {
    let res_path = dir.join(filename);
    println!("Writing {}", res_path.to_string_lossy());
    let mut file = fs::File::create(res_path)?;
    file.write_all(bytes)?;
    Ok(())
}

pub(crate) fn uninstall() -> Result<()> {
    let kernel_dir = get_kernel_dir()?;
    println!("Deleting {}", kernel_dir.to_string_lossy());
    fs::remove_dir_all(kernel_dir)?;
    println!("Uninstall complete");
    Ok(())
}

// https://jupyter-client.readthedocs.io/en/latest/kernels.html
fn get_kernel_dir() -> Result<PathBuf> {
    let jupyter_dir = if let Ok(dir) = env::var("JUPYTER_PATH") {
        PathBuf::from(dir)
    } else if let Some(dir) = get_user_kernel_dir() {
        dir
    } else {
        bail!("Couldn't get XDG data directory");
    };
    Ok(jupyter_dir.join("kernels").join("rust"))
}

#[cfg(not(target_os = "macos"))]
fn get_user_kernel_dir() -> Option<PathBuf> {
    dirs::data_dir().map(|data_dir| data_dir.join("jupyter"))
}

#[cfg(target_os = "macos")]
fn get_user_kernel_dir() -> Option<PathBuf> {
    dirs::data_dir().and_then(|d| d.parent().map(|data_dir| data_dir.join("Jupyter")))
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * kit/kernel/kernel.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 * Based on OSDev Bare Bones tutorial
 * http://wiki.osdev.org/Bare_Bones
 *
 ******************************************************************************/

//! The Kit kernel.

#![crate_name="kernel"]
#![crate_type="lib"]

#![feature(core)]
#![feature(unique)]
#![feature(libc)]
#![feature(asm)]
#![feature(no_std)]
#![feature(lang_items)]
#![feature(unsafe_destructor)]

#![no_std]

#[macro_use]
extern crate core;

// No linkage. Mostly for types.
extern crate libc;

use core::prelude::*;
use core::iter::range_inclusive;

pub mod terminal;
pub mod constants;
pub mod multiboot;
pub mod memory;
pub mod collections;
pub mod interrupt;
pub mod paging;
pub mod keyboard;
pub mod archive;
pub mod process;
pub mod elf;
pub mod scheduler;
pub mod shell;
pub mod c_ffi;

use terminal::*;
use elf::Elf;
use process::Process;
use shell::shell;

use c_ffi::CStr;

/// Main kernel entry point.
#[no_mangle]
pub extern fn kernel_main() -> ! {

    console().reset().unwrap();
    console().set_color(Color::Red, Color::White).unwrap();

    console().write_str("+ Hello, I'm Kit.\n").unwrap();

    console().set_color(Color::White, Color::Red).unwrap();
    console().write_char('\n').unwrap();

    let mb_info = unsafe { multiboot::get_info() };

    match mb_info.mem_sizes() {
        Some((lower, upper)) => {
            write!(console(),
                   "{:<20} {:<10} KiB\n\
                    {:<20} {:<10} KiB\n",
                   "Lower memory:", lower,
                   "Upper memory:", upper).unwrap();
        },
        None => {
            write!(console(),
                   "W: Bootloader did not provide valid memory information!")
                .unwrap();
        }
    }

    match unsafe { mb_info.cmdline() } {
        Some(cmdline) => {
            write!(console(), "{:<20} ", "Kernel command line:").unwrap();

            console().write_raw_bytes(cmdline.as_bytes()).unwrap();
            console().write_char('\n').unwrap();
        },
        None => {
            write!(console(), "Kernel command line:\n").unwrap();
        }
    }

    console().write_char('\n').unwrap();
    console().set_color(Color::LightGrey, Color::Black).unwrap();
    console().write_char('\n').unwrap();

    if mb_info.flags & multiboot::info_flags::MEM_MAP != 0 {
        unsafe {
            let mmap = constants::translate_low_addr(mb_info.mmap_addr)
                .expect("mmap pointer outside low region");

            memory::initialize(mmap, mb_info.mmap_length);
        }
    } else {
        panic!("Bootloader did not provide memory map!");
    }

    unsafe {
        interrupt::initialize();
        paging::initialize();
        memory::enable_large_heap();
        keyboard::initialize().unwrap();
    }

    if mb_info.flags & multiboot::info_flags::MODS != 0 {
        unsafe {
            let mods = constants::translate_low_addr(mb_info.mods_addr)
                .expect("mods pointer outside low region");

            if !archive::initialize(mods, mb_info.mods_count) {
                panic!("Archive initialization failed. Are you sure \
                        system.kit was provided?");
            }
        }
    } else {
        panic!("Bootloader did not provide modules!");
    }

    {
        let mut tree = collections::TreeMap::<i32,()>::new();

        for n in range_inclusive(1, 16) {
            tree.insert(n,());
        }

        for n in range_inclusive(1, 16) {
            tree.delete(&n).unwrap();
            write!(console(), "{} => {:?}\n", n, tree).unwrap();
        }

    }

    unsafe {
        process::initialize();
    }

    {
        let cmdline = unsafe { mb_info.cmdline().unwrap() };

        if !cmdline.is_empty() {
            spawn_init(cmdline).unwrap();
        } else {
            write!(console(), "W: No initial program specified on kernel \
                               command line; dropping into kernel\n   \
                               shell.\n").unwrap();

            unsafe {
                interrupt::enable();
                shell();
            }
        }
    }

    unreachable!();
}

#[derive(Debug)]
enum SpawnInitError {
    NoProgramSpecified,
    FileNotFound,
    ElfVerifyError,
    ProcessCreateError,
    ElfLoadError,
    SetArgsError
}
use SpawnInitError::*;

fn spawn_init<'a>(filename: CStr<'static>) -> Result<(), SpawnInitError> {

    console().set_color(Color::White, Color::Magenta).unwrap();

    if filename.is_empty() {
        return Err(NoProgramSpecified);
    }

    let system = archive::system();

    let data = try!(system.get(filename).ok_or(FileNotFound));

    let elf = try!(Elf::new(data).ok_or(ElfVerifyError));

    let mut process = try!(Process::new(filename).ok_or(ProcessCreateError));

    if !process.load(&elf) {
        return Err(ElfLoadError)
    }

    if !process.set_args(&[filename.as_ptr()]) {
        return Err(SetArgsError)
    }

    console().set_color(Color::LightGrey, Color::Black).unwrap();

    process.run();

    unsafe { scheduler::enter(); }

    Ok(())
}

#[lang = "stack_exhausted"]
extern fn stack_exhausted() {
}

#[lang = "eh_personality"]
extern fn eh_personality() {
}

#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: core::fmt::Arguments,
                    file: &'static str,
                    line: usize) -> ! {

    let _ = console().set_color(Color::White, Color::Red);

    let _ = write!(console(), "\nKernel panic in {}:{}:\n  {}\n\n",
                   file, line, fmt);

    unsafe {
        loop { asm!("cli; hlt" :::: "volatile"); }
    }
}
<commit_msg>[kernel] remove the tree test<commit_after>/*******************************************************************************
 *
 * kit/kernel/kernel.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 * Based on OSDev Bare Bones tutorial
 * http://wiki.osdev.org/Bare_Bones
 *
 ******************************************************************************/

//! The Kit kernel.

#![crate_name="kernel"]
#![crate_type="lib"]

#![feature(core)]
#![feature(unique)]
#![feature(libc)]
#![feature(asm)]
#![feature(no_std)]
#![feature(lang_items)]
#![feature(unsafe_destructor)]

#![no_std]

#[macro_use]
extern crate core;

// No linkage. Mostly for types.
extern crate libc;

use core::prelude::*;

pub mod terminal;
pub mod constants;
pub mod multiboot;
pub mod memory;
pub mod collections;
pub mod interrupt;
pub mod paging;
pub mod keyboard;
pub mod archive;
pub mod process;
pub mod elf;
pub mod scheduler;
pub mod shell;
pub mod c_ffi;

use terminal::*;
use elf::Elf;
use process::Process;
use shell::shell;

use c_ffi::CStr;

/// Main kernel entry point.
#[no_mangle]
pub extern fn kernel_main() -> ! {

    console().reset().unwrap();
    console().set_color(Color::Red, Color::White).unwrap();

    console().write_str("+ Hello, I'm Kit.\n").unwrap();

    console().set_color(Color::White, Color::Red).unwrap();
    console().write_char('\n').unwrap();

    let mb_info = unsafe { multiboot::get_info() };

    match mb_info.mem_sizes() {
        Some((lower, upper)) => {
            write!(console(),
                   "{:<20} {:<10} KiB\n\
                    {:<20} {:<10} KiB\n",
                   "Lower memory:", lower,
                   "Upper memory:", upper).unwrap();
        },
        None => {
            write!(console(),
                   "W: Bootloader did not provide valid memory information!")
                .unwrap();
        }
    }

    match unsafe { mb_info.cmdline() } {
        Some(cmdline) => {
            write!(console(), "{:<20} ", "Kernel command line:").unwrap();

            console().write_raw_bytes(cmdline.as_bytes()).unwrap();
            console().write_char('\n').unwrap();
        },
        None => {
            write!(console(), "Kernel command line:\n").unwrap();
        }
    }

    console().write_char('\n').unwrap();
    console().set_color(Color::LightGrey, Color::Black).unwrap();
    console().write_char('\n').unwrap();

    if mb_info.flags & multiboot::info_flags::MEM_MAP != 0 {
        unsafe {
            let mmap = constants::translate_low_addr(mb_info.mmap_addr)
                .expect("mmap pointer outside low region");

            memory::initialize(mmap, mb_info.mmap_length);
        }
    } else {
        panic!("Bootloader did not provide memory map!");
    }

    unsafe {
        interrupt::initialize();
        paging::initialize();
        memory::enable_large_heap();
        keyboard::initialize().unwrap();
    }

    if mb_info.flags & multiboot::info_flags::MODS != 0 {
        unsafe {
            let mods = constants::translate_low_addr(mb_info.mods_addr)
                .expect("mods pointer outside low region");

            if !archive::initialize(mods, mb_info.mods_count) {
                panic!("Archive initialization failed. Are you sure \
                        system.kit was provided?");
            }
        }
    } else {
        panic!("Bootloader did not provide modules!");
    }

    unsafe {
        process::initialize();
    }

    {
        let cmdline = unsafe { mb_info.cmdline().unwrap() };

        if !cmdline.is_empty() {
            spawn_init(cmdline).unwrap();
        } else {
            write!(console(), "W: No initial program specified on kernel \
                               command line; dropping into kernel\n   \
                               shell.\n").unwrap();

            unsafe {
                interrupt::enable();
                shell();
            }
        }
    }

    unreachable!();
}

#[derive(Debug)]
enum SpawnInitError {
    NoProgramSpecified,
    FileNotFound,
    ElfVerifyError,
    ProcessCreateError,
    ElfLoadError,
    SetArgsError
}
use SpawnInitError::*;

fn spawn_init<'a>(filename: CStr<'static>) -> Result<(), SpawnInitError> {

    console().set_color(Color::White, Color::Magenta).unwrap();

    if filename.is_empty() {
        return Err(NoProgramSpecified);
    }

    let system = archive::system();

    let data = try!(system.get(filename).ok_or(FileNotFound));

    let elf = try!(Elf::new(data).ok_or(ElfVerifyError));

    let mut process = try!(Process::new(filename).ok_or(ProcessCreateError));

    if !process.load(&elf) {
        return Err(ElfLoadError)
    }

    if !process.set_args(&[filename.as_ptr()]) {
        return Err(SetArgsError)
    }

    console().set_color(Color::LightGrey, Color::Black).unwrap();

    process.run();

    unsafe { scheduler::enter(); }

    Ok(())
}

#[lang = "stack_exhausted"]
extern fn stack_exhausted() {
}

#[lang = "eh_personality"]
extern fn eh_personality() {
}

#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: core::fmt::Arguments,
                    file: &'static str,
                    line: usize) -> ! {

    let _ = console().set_color(Color::White, Color::Red);

    let _ = write!(console(), "\nKernel panic in {}:{}:\n  {}\n\n",
                   file, line, fmt);

    unsafe {
        loop { asm!("cli; hlt" :::: "volatile"); }
    }
}
<|endoftext|>


<commit_before>use clap::App;

pub struct ArgValues {
    pub width: f32,
    pub height: f32,
    pub shaderpath: String,
    pub not_from_shadertoy: bool,
    pub texture0path: String,
    pub texture1path: String,
    pub texture2path: String,
    pub texture3path: String,
}

impl ArgValues {
    pub fn from_cli() -> Result<ArgValues, String> {
        // Load CLI matches
        let yaml = load_yaml!("cli.yml");
        let matches = App::from_yaml(yaml).get_matches();

        // Width
        let width: f32;
        match matches.value_of("width").unwrap().parse() {
            Ok(w)  => width = w,
            Err(e) => return Err(format!("Invalid width: {}", e)),
        }

        // Height
        let height: f32;
        match matches.value_of("height").unwrap().parse() {
            Ok(h)  => height = h,
            Err(e) => return Err(format!("Invalid height: {}", e)),
        }

        // Check to see if they want an example run
        let (shaderpath, not_from_shadertoy) = if matches.is_present("example") {
            let example = matches.value_of("example").unwrap();
            let shaderpath = if example.contains(".frag") {
                format!("examples/{}", example)
            } else {
                format!("examples/{}.frag", example)
            };
            (shaderpath, false)
        } else {
            let shaderpath = matches.value_of("shader").unwrap().to_string();
            let not_from_shadertoy = if matches.is_present("shader") {
                matches.is_present("not_from_shadertoy")
            } else {
                false
            };
            (shaderpath, not_from_shadertoy)
        };

        // Texture paths
        let texture0path = matches.value_of("texture0").unwrap().to_string();
        let texture1path = matches.value_of("texture1").unwrap().to_string();
        let texture2path = matches.value_of("texture2").unwrap().to_string();
        let texture3path = matches.value_of("texture3").unwrap().to_string();

        Ok(ArgValues {
            width: width,
            height: height,
            shaderpath: shaderpath,
            not_from_shadertoy: not_from_shadertoy,
            texture0path: texture0path,
            texture1path: texture1path,
            texture2path: texture2path,
            texture3path: texture3path,
        })
    }

    pub fn from_values(width: f32, height: f32, shaderpath: &str, not_from_shadertoy: bool) -> ArgValues {
        ArgValues {
            width: width,
            height: height,
            shaderpath: shaderpath.to_string(),
            not_from_shadertoy: not_from_shadertoy,
            texture0path: "textures/01-brickwall.jpg".to_string(),
            texture1path: "textures/02-landscape.jpg".to_string(),
            texture2path: "textures/03-whitenoise.jpg".to_string(),
            texture3path: "textures/04-woodgrain.jpg".to_string(),
        }
    }
}
<commit_msg>Remove unused function from_values()<commit_after>use clap::App;

pub struct ArgValues {
    pub width: f32,
    pub height: f32,
    pub shaderpath: String,
    pub not_from_shadertoy: bool,
    pub texture0path: String,
    pub texture1path: String,
    pub texture2path: String,
    pub texture3path: String,
}

impl ArgValues {
    pub fn from_cli() -> Result<ArgValues, String> {
        // Load CLI matches
        let yaml = load_yaml!("cli.yml");
        let matches = App::from_yaml(yaml).get_matches();

        // Width
        let width: f32;
        match matches.value_of("width").unwrap().parse() {
            Ok(w)  => width = w,
            Err(e) => return Err(format!("Invalid width: {}", e)),
        }

        // Height
        let height: f32;
        match matches.value_of("height").unwrap().parse() {
            Ok(h)  => height = h,
            Err(e) => return Err(format!("Invalid height: {}", e)),
        }

        // Check to see if they want an example run
        let (shaderpath, not_from_shadertoy) = if matches.is_present("example") {
            let example = matches.value_of("example").unwrap();
            let shaderpath = if example.contains(".frag") {
                format!("examples/{}", example)
            } else {
                format!("examples/{}.frag", example)
            };
            (shaderpath, false)
        } else {
            let shaderpath = matches.value_of("shader").unwrap().to_string();
            let not_from_shadertoy = if matches.is_present("shader") {
                matches.is_present("not_from_shadertoy")
            } else {
                false
            };
            (shaderpath, not_from_shadertoy)
        };

        // Texture paths
        let texture0path = matches.value_of("texture0").unwrap().to_string();
        let texture1path = matches.value_of("texture1").unwrap().to_string();
        let texture2path = matches.value_of("texture2").unwrap().to_string();
        let texture3path = matches.value_of("texture3").unwrap().to_string();

        Ok(ArgValues {
            width: width,
            height: height,
            shaderpath: shaderpath,
            not_from_shadertoy: not_from_shadertoy,
            texture0path: texture0path,
            texture1path: texture1path,
            texture2path: texture2path,
            texture3path: texture3path,
        })
    }
}
<|endoftext|>


<commit_before>//! Three-dimensional points with additional attributes.

mod classification;
mod format;
mod point;
mod scan_direction;

pub use point::classification::Classification;
pub use point::format::Format;
pub use point::point::Point;
pub use point::scan_direction::ScanDirection;

quick_error! {
    /// Point-specific errors
    #[derive(Debug, Clone, Copy)]
    pub enum Error {
        /// An invalid classification number.
        Classification(n: u8) {
            description("invalid classification")
            display("invalid classification: {}", n)
        }
        /// This is an invalid format.
        ///
        /// It has a combination of options that can't exist.
        Format(format: Format) {
            description("invalid format")
            display("invalid format: {:?}", format)
        }
        /// This is an invalid format number.
        FormatNumber(n: u8) {
            description("invalid format number")
            display("invalid format number: {:?}", n)
        }
        /// This is not a valid return number.
        ReturnNumber(n: u8, version: Option<::Version>) {
            description("invalid return number")
            display("invalid return number: {} (for version: {:?})", n, version)
        }
        /// This is not a valid scanner channel
        ScannerChannel(n: u8) {
            description("invalid scanner channel")
            display("the scanner channel is invalid: {}", n)
        }
    }
}
<commit_msg>Use self in point mod exports<commit_after>//! Three-dimensional points with additional attributes.

mod classification;
mod format;
mod point;
mod scan_direction;

pub use self::classification::Classification;
pub use self::format::Format;
pub use self::point::Point;
pub use self::scan_direction::ScanDirection;

quick_error! {
    /// Point-specific errors
    #[derive(Debug, Clone, Copy)]
    pub enum Error {
        /// An invalid classification number.
        Classification(n: u8) {
            description("invalid classification")
            display("invalid classification: {}", n)
        }
        /// This is an invalid format.
        ///
        /// It has a combination of options that can't exist.
        Format(format: Format) {
            description("invalid format")
            display("invalid format: {:?}", format)
        }
        /// This is an invalid format number.
        FormatNumber(n: u8) {
            description("invalid format number")
            display("invalid format number: {:?}", n)
        }
        /// This is not a valid return number.
        ReturnNumber(n: u8, version: Option<::Version>) {
            description("invalid return number")
            display("invalid return number: {} (for version: {:?})", n, version)
        }
        /// This is not a valid scanner channel
        ScannerChannel(n: u8) {
            description("invalid scanner channel")
            display("the scanner channel is invalid: {}", n)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 Torste Aikio and gl-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.

#[feature(globs)];
#[feature(macro_rules)];

extern mod glfw;
extern mod gl;

use std::libc;

use std::cast;
use std::ptr;
use std::str;
use std::sys;
use std::vec;

use gl::types::*;

// Vertex data
static VERTEX_DATA: [GLfloat, ..8] = [
    -1.0,  1.0,
    -1.0, -1.0,
     1.0,  1.0,
     1.0, -1.0
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 vertex;\n\
    uniform vec2 scale;\n\
    uniform vec2 position;\n\
    void main() {\n\
       vec2 out_vert = vertex * scale;\n\
       out_vert += position;\n\
       gl_Position = vec4(out_vert, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint, out_color: &str) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    // gl::BindFragDataLocation needs to be called before linking to have effect
    unsafe {
        out_color.with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));
    }
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    program
}

fn main() {
    do glfw::set_error_callback |_, description| {
        println!("GLFW Error: {}", description);
    }

    do glfw::start {
        // Choose a GL profile that is compatible with OS X 10.7+
        glfw::window_hint::context_version(3, 2);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::opengl_forward_compat(true);

        let window = glfw::Window::create(600, 600, "Pong", glfw::Windowed).unwrap();
        window.set_key_callback(key_callback);
        window.make_context_current();

        // Load the OpenGL function pointers
        gl::load_with(glfw::get_proc_address);

        // Create GLSL shaders
        let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
        let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
        let program = link_program(vs, fs, "out_color");

        let mut vao = 0;
        let mut vbo = 0;

        let position_uniform: GLint;
        let scale_uniform: GLint;

        unsafe {
            position_uniform = "position".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            scale_uniform = "scale".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            // Create Vertex Array Object
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl::GenBuffers(1, &mut vbo);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(gl::ARRAY_BUFFER,
                           (VERTEX_DATA.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                           cast::transmute(&VERTEX_DATA[0]),
                           gl::STATIC_DRAW);

            // Use shader program
            gl::UseProgram(program);

            // Specify the layout of the vertex data
            let vert_attr = "vertex".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(vert_attr as GLuint);
            gl::VertexAttribPointer(vert_attr as GLuint, 2, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());
        }

        while !window.should_close() {
            // Poll events
            glfw::poll_events();

            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Set uniforms
            gl::ProgramUniform2f(program, position_uniform, 0.8, 0.0);
            gl::ProgramUniform2f(program, scale_uniform, 0.05, 0.2);
            // Draw a rect from the 4 vertices
            gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

            // lets draw another rect

            // Set uniforms
            gl::ProgramUniform2f(program, position_uniform, -0.8, 0.0);
            gl::ProgramUniform2f(program, scale_uniform, 0.05, 0.2);
            // Draw a rect from the 4 vertices
            gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

            // and a cube

            // Set uniforms
            gl::ProgramUniform2f(program, position_uniform, 0.0, 0.0);
            gl::ProgramUniform2f(program, scale_uniform, 0.025, 0.025);
            // Draw a rect from the 4 vertices
            gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

            // Swap buffers
            window.swap_buffers();
        }

        // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        unsafe {
            gl::DeleteBuffers(1, &vbo);
            gl::DeleteVertexArrays(1, &vao);
        }
    }
}

fn key_callback(window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
    if action == glfw::Press && key == glfw::KeyEscape {
        window.set_should_close(true);
    }
}
<commit_msg>changed window size to widescreen<commit_after>// Copyright 2013 Torste Aikio and gl-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.

#[feature(globs)];
#[feature(macro_rules)];

extern mod glfw;
extern mod gl;

use std::libc;

use std::cast;
use std::ptr;
use std::str;
use std::sys;
use std::vec;

use gl::types::*;

// Vertex data
static VERTEX_DATA: [GLfloat, ..8] = [
    -1.0,  1.0,
    -1.0, -1.0,
     1.0,  1.0,
     1.0, -1.0
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 vertex;\n\
    uniform vec2 scale;\n\
    uniform vec2 position;\n\
    void main() {\n\
       vec2 out_vert = vertex * scale;\n\
       out_vert += position;\n\
       gl_Position = vec4(out_vert, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint, out_color: &str) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    // gl::BindFragDataLocation needs to be called before linking to have effect
    unsafe {
        out_color.with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));
    }
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    program
}

fn main() {
    do glfw::set_error_callback |_, description| {
        println!("GLFW Error: {}", description);
    }

    do glfw::start {
        // Choose a GL profile that is compatible with OS X 10.7+
        glfw::window_hint::context_version(3, 2);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::opengl_forward_compat(true);

        let window = glfw::Window::create(1024, 600, "Pong", glfw::Windowed).unwrap();
        window.set_key_callback(key_callback);
        window.make_context_current();

        // Load the OpenGL function pointers
        gl::load_with(glfw::get_proc_address);

        // Create GLSL shaders
        let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
        let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
        let program = link_program(vs, fs, "out_color");

        let mut vao = 0;
        let mut vbo = 0;

        let position_uniform: GLint;
        let scale_uniform: GLint;

        unsafe {
            position_uniform = "position".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            scale_uniform = "scale".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            // Create Vertex Array Object
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl::GenBuffers(1, &mut vbo);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(gl::ARRAY_BUFFER,
                           (VERTEX_DATA.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                           cast::transmute(&VERTEX_DATA[0]),
                           gl::STATIC_DRAW);

            // Use shader program
            gl::UseProgram(program);

            // Specify the layout of the vertex data
            let vert_attr = "vertex".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(vert_attr as GLuint);
            gl::VertexAttribPointer(vert_attr as GLuint, 2, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());
        }

        while !window.should_close() {
            // Poll events
            glfw::poll_events();

            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Set uniforms
            gl::ProgramUniform2f(program, position_uniform, 0.8, 0.0);
            gl::ProgramUniform2f(program, scale_uniform, 0.05, 0.2);
            // Draw a rect from the 4 vertices
            gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

            // lets draw another rect

            // Set uniforms
            gl::ProgramUniform2f(program, position_uniform, -0.8, 0.0);
            gl::ProgramUniform2f(program, scale_uniform, 0.05, 0.2);
            // Draw a rect from the 4 vertices
            gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

            // and a cube

            // Set uniforms
            gl::ProgramUniform2f(program, position_uniform, 0.0, 0.0);
            gl::ProgramUniform2f(program, scale_uniform, 0.025, 0.025);
            // Draw a rect from the 4 vertices
            gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

            // Swap buffers
            window.swap_buffers();
        }

        // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        unsafe {
            gl::DeleteBuffers(1, &vbo);
            gl::DeleteVertexArrays(1, &vao);
        }
    }
}

fn key_callback(window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
    if action == glfw::Press && key == glfw::KeyEscape {
        window.set_should_close(true);
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;

pub trait Automaton<Input: Ord> {
    type State: Debug;

    fn start_state() -> Self::State;
    fn stuck_state() -> Self::State;

    fn next_state(&self, state: &Self::State, input: &Input) -> Self::State;

    fn has_match(&self, si: &Self::State, patt_no_offset: usize) -> bool;

    fn get_match(&self, si: &Self::State, patt_no_offset: usize, text_offset: usize) -> Match;

    fn find<'i, 'a>(&'a self, s: &'i [Input]) -> Matches<'i, 'a, Input, Self>
        where Self: Sized
    {
        Matches {
            aut: self,
            input: s,
            offset: 0,
            state: Self::start_state(),
        }
    }
}

// This is from burntsushi/aho-corasick.
/// Records a match in the search text.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Match {
    /// The pattern index.
    ///
    /// This corresponds to the ordering in which the matched pattern was
    /// added to the automaton, starting at `0`.
    pub patt_no: usize,
    /// The starting byte offset of the match in the search text.
    pub start: usize,
    /// The ending byte offset of the match in the search text.
    ///
    /// (This can be re-capitulated with `pattern_no` and adding the pattern's
    /// length to `start`, but it is convenient to have it here.)
    pub end: usize,
}

/// An iterator of non-overlapping matches for in-memory text.
///
/// This iterator yields `Match` values.
#[derive(Debug)]
pub struct Matches<'i, 'a, Input: 'i + Ord, A: 'a + Automaton<Input>> {
    aut: &'a A,
    input: &'i [Input],
    offset: usize,
    state: A::State,
}

impl<'i, 'a, Input: Ord, A: Automaton<Input>> Iterator for Matches<'i, 'a, Input, A> {
    type Item = Match;

    fn next(&mut self) -> Option<Match> {
        let mut offset = self.offset;
        while offset < self.input.len() {
            self.state = self.aut.next_state(&self.state, &self.input[offset]);
            if self.aut.has_match(&self.state, 0) {
                break;
            }
            offset += 1;
        }
        if offset < self.input.len() {
            offset += 1;
            self.offset = offset;
            Some(self.aut.get_match(&self.state, 0, offset))
        } else {
            None
        }
    }
}
<commit_msg>Changed Iterator impl for Matches to a simpler control-flow<commit_after>use std::fmt::Debug;

pub trait Automaton<Input: Ord> {
    type State: Debug;

    fn start_state() -> Self::State;
    fn stuck_state() -> Self::State;

    fn next_state(&self, state: &Self::State, input: &Input) -> Self::State;

    fn has_match(&self, si: &Self::State, patt_no_offset: usize) -> bool;

    fn get_match(&self, si: &Self::State, patt_no_offset: usize, text_offset: usize) -> Match;

    fn find<'i, 'a>(&'a self, s: &'i [Input]) -> Matches<'i, 'a, Input, Self>
        where Self: Sized
    {
        Matches {
            aut: self,
            input: s,
            offset: 0,
            state: Self::start_state(),
        }
    }
}

// This is from burntsushi/aho-corasick.
/// Records a match in the search text.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Match {
    /// The pattern index.
    ///
    /// This corresponds to the ordering in which the matched pattern was
    /// added to the automaton, starting at `0`.
    pub patt_no: usize,
    /// The starting byte offset of the match in the search text.
    pub start: usize,
    /// The ending byte offset of the match in the search text.
    ///
    /// (This can be re-capitulated with `pattern_no` and adding the pattern's
    /// length to `start`, but it is convenient to have it here.)
    pub end: usize,
}

/// An iterator of non-overlapping matches for in-memory text.
///
/// This iterator yields `Match` values.
#[derive(Debug)]
pub struct Matches<'i, 'a, Input: 'i + Ord, A: 'a + Automaton<Input>> {
    aut: &'a A,
    input: &'i [Input],
    offset: usize,
    state: A::State,
}

impl<'i, 'a, Input: Ord, A: Automaton<Input>> Iterator for Matches<'i, 'a, Input, A> {
    type Item = Match;

    fn next(&mut self) -> Option<Match> {
        let mut offset = self.offset;
        while offset < self.input.len() {
            self.state = self.aut.next_state(&self.state, &self.input[offset]);
            offset += 1;
            if self.aut.has_match(&self.state, 0) {
                self.offset = offset;
                return Some(self.aut.get_match(&self.state, 0, offset));
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>//! Actix web juniper example
//!
//! A simple example integrating juniper in actix-web
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate juniper;
extern crate futures;
extern crate actix;
extern crate actix_web;
extern crate env_logger;

use actix::prelude::*;
use actix_web::{
    middleware, http::{self, header::CONTENT_TYPE}, server,
    App, AsyncResponder, HttpRequest, HttpResponse, HttpMessage, Error};
use juniper::http::graphiql::graphiql_source;
use juniper::http::GraphQLRequest;

use futures::future::Future;

mod schema;

use schema::Schema;
use schema::create_schema;

struct State {
    executor: Addr<Syn, GraphQLExecutor>,
}

#[derive(Serialize, Deserialize)]
pub struct GraphQLData(GraphQLRequest);

impl Message for GraphQLData {
    type Result = Result<String, Error>;
}

pub struct GraphQLExecutor {
    schema: std::sync::Arc<Schema>
}

impl GraphQLExecutor {
    fn new(schema: std::sync::Arc<Schema>) -> GraphQLExecutor {
        GraphQLExecutor {
            schema: schema,
        }
    }
}

impl Actor for GraphQLExecutor {
    type Context = SyncContext<Self>;
}

impl Handler<GraphQLData> for GraphQLExecutor {
    type Result = Result<String, Error>;

    fn handle(&mut self, msg: GraphQLData, _: &mut Self::Context) -> Self::Result {
        let res = msg.0.execute(&self.schema, &());
        let res_text = serde_json::to_string(&res)?;
        Ok(res_text)
    }
}

fn graphiql(_req: HttpRequest<State>) -> Result<HttpResponse, Error>  {
    let html = graphiql_source("http://127.0.0.1:8080/graphql");
    Ok(HttpResponse::Ok()
        .content_type("text/html; charset=utf-8")
        .body(html))
}

fn graphql(req: HttpRequest<State>) -> Box<Future<Item=HttpResponse, Error=Error>> {
    let executor = req.state().executor.clone();
    req.json()
        .from_err()
        .and_then(move |val: GraphQLData| {
            executor.send(val)
                .from_err()
                .and_then(|res| {
                    match res {
                        Ok(user) => Ok(HttpResponse::Ok().header(CONTENT_TYPE, "application/json").body(user)),
                        Err(_) => Ok(HttpResponse::InternalServerError().into())
                    }
                })
        })
        .responder()
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _ = env_logger::init();
    let sys = actix::System::new("juniper-example");

    let schema = std::sync::Arc::new(create_schema());
    let addr = SyncArbiter::start(3, move || {
        GraphQLExecutor::new(schema.clone())
    });

    // Start http server
    let _ = server::new(move || {
        App::with_state(State{executor: addr.clone()})
            // enable logger
            .middleware(middleware::Logger::default())
            .resource("/graphql", |r| r.method(http::Method::POST).h(graphql))
            .resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql))})
        .bind("127.0.0.1:8080").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
<commit_msg>update juniper example<commit_after>//! Actix web juniper example
//!
//! A simple example integrating juniper in actix-web
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate juniper;
extern crate futures;
extern crate actix;
extern crate actix_web;
extern crate env_logger;

use actix::prelude::*;
use actix_web::{
    middleware, http, server,
    App, AsyncResponder, HttpRequest, HttpResponse, FutureResponse, Error, State, Json};
use juniper::http::graphiql::graphiql_source;
use juniper::http::GraphQLRequest;
use futures::future::Future;

mod schema;

use schema::Schema;
use schema::create_schema;

struct AppState {
    executor: Addr<Syn, GraphQLExecutor>,
}

#[derive(Serialize, Deserialize)]
pub struct GraphQLData(GraphQLRequest);

impl Message for GraphQLData {
    type Result = Result<String, Error>;
}

pub struct GraphQLExecutor {
    schema: std::sync::Arc<Schema>
}

impl GraphQLExecutor {
    fn new(schema: std::sync::Arc<Schema>) -> GraphQLExecutor {
        GraphQLExecutor {
            schema: schema,
        }
    }
}

impl Actor for GraphQLExecutor {
    type Context = SyncContext<Self>;
}

impl Handler<GraphQLData> for GraphQLExecutor {
    type Result = Result<String, Error>;

    fn handle(&mut self, msg: GraphQLData, _: &mut Self::Context) -> Self::Result {
        let res = msg.0.execute(&self.schema, &());
        let res_text = serde_json::to_string(&res)?;
        Ok(res_text)
    }
}

fn graphiql(_req: HttpRequest<AppState>) -> Result<HttpResponse, Error>  {
    let html = graphiql_source("http://127.0.0.1:8080/graphql");
    Ok(HttpResponse::Ok()
       .content_type("text/html; charset=utf-8")
       .body(html))
}

fn graphql(st: State<AppState>, data: Json<GraphQLData>) -> FutureResponse<HttpResponse> {
    st.executor.send(data.0)
        .from_err()
        .and_then(|res| {
            match res {
                Ok(user) => Ok(HttpResponse::Ok()
                               .content_type("application/json")
                               .body(user)),
                Err(_) => Ok(HttpResponse::InternalServerError().into())
            }
        })
        .responder()
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let sys = actix::System::new("juniper-example");

    let schema = std::sync::Arc::new(create_schema());
    let addr = SyncArbiter::start(3, move || {
        GraphQLExecutor::new(schema.clone())
    });

    // Start http server
    let _ = server::new(move || {
        App::with_state(AppState{executor: addr.clone()})
            // enable logger
            .middleware(middleware::Logger::default())
            .resource("/graphql", |r| r.method(http::Method::POST).with2(graphql))
            .resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql))})
        .bind("127.0.0.1:8080").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
<|endoftext|>


<commit_before>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate handlebars;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate semver;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::io;
use std::fmt;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The date that the build was performed.
    pub build_date: String,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: String,
    pub minor: String,
    pub patch: String,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo-{}.{}.{}",
               self.major, self.minor, self.patch)?;
        match self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            Some(channel) => {
                if channel != "stable" {
                    write!(f, "-{}", channel)?;
                    let empty = String::from("");
                    write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
                }
            },
            None => (),
        };

        if let Some(ref cfg) = self.cfg_info {
            match cfg.commit_info {
                Some(ref ci) => {
                    write!(f, " ({} {})",
                           ci.short_commit_hash, ci.commit_date)?;
                },
                None => {
                    write!(f, " (built {})",
                           cfg.build_date)?;
                }
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: Decodable>(
            exec: fn(Flags, &Config) -> CliResult,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: Encodable>(obj: &T) {
    let encoded = json::encode(&obj).unwrap();
    println!("{}", encoded);
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> VersionInfo {
    macro_rules! env_str {
        ($name:expr) => { env!($name).to_string() }
    }
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }
    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major: option_env_str!("CFG_VERSION_MAJOR").unwrap(),
                minor: option_env_str!("CFG_VERSION_MINOR").unwrap(),
                patch: option_env_str!("CFG_VERSION_PATCH").unwrap(),
                pre_release: option_env_str!("CFG_PRERELEASE_VERSION"),
                cfg_info: Some(CfgInfo {
                    build_date: option_env_str!("CFG_BUILD_DATE").unwrap(),
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info: commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<commit_msg>Auto merge of #3730 - froydnj:cargo-version-dash-fix, r=alexcrichton<commit_after>#![deny(unused)]
#![cfg_attr(test, deny(warnings))]

#[cfg(test)] extern crate hamcrest;
#[macro_use] extern crate log;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate handlebars;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate semver;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate toml;
extern crate url;

use std::io;
use std::fmt;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json;
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig};
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};

pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};

macro_rules! bail {
    ($($fmt:tt)*) => (
        return Err(::util::human(&format_args!($($fmt)*)))
    )
}

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The date that the build was performed.
    pub build_date: String,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: String,
    pub minor: String,
    pub patch: String,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo {}.{}.{}",
               self.major, self.minor, self.patch)?;
        match self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            Some(channel) => {
                if channel != "stable" {
                    write!(f, "-{}", channel)?;
                    let empty = String::from("");
                    write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
                }
            },
            None => (),
        };

        if let Some(ref cfg) = self.cfg_info {
            match cfg.commit_info {
                Some(ref ci) => {
                    write!(f, " ({} {})",
                           ci.short_commit_hash, ci.commit_date)?;
                },
                None => {
                    write!(f, " (built {})",
                           cfg.build_date)?;
                }
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: Decodable>(
            exec: fn(Flags, &Config) -> CliResult,
            config: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(human(e.to_string()), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: Encodable>(obj: &T) {
    let encoded = json::encode(&obj).unwrap();
    println!("{}", encoded);
}

pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell {
    enum Output {
        Stdout,
        Stderr,
    }

    let tty = isatty(Output::Stderr);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let err = Shell::create(|| Box::new(io::stderr()), config);

    let tty = isatty(Output::Stdout);

    let config = ShellConfig { color_config: color_config, tty: tty };
    let out = Shell::create(|| Box::new(io::stdout()), config);

    return MultiShell::new(out, err, verbosity);

    #[cfg(unix)]
    fn isatty(output: Output) -> bool {
        let fd = match output {
            Output::Stdout => libc::STDOUT_FILENO,
            Output::Stderr => libc::STDERR_FILENO,
        };

        unsafe { libc::isatty(fd) != 0 }
    }
    #[cfg(windows)]
    fn isatty(output: Output) -> bool {
        extern crate kernel32;
        extern crate winapi;

        let handle = match output {
            Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE,
            Output::Stderr => winapi::winbase::STD_ERROR_HANDLE,
        };

        unsafe {
            let handle = kernel32::GetStdHandle(handle);
            let mut out = 0;
            kernel32::GetConsoleMode(handle, &mut out) != 0
        }
    }
}

pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.get_verbose() != Verbose;

    if let Some(error) = error {
        let _ignored_result = if hide {
            shell.error("An unknown error occurred")
        } else if fatal {
            shell.error(&error)
        } else {
            shell.say(&error, BLACK)
        };

        if !handle_cause(&error, shell) || hide {
            let _ = shell.err().say("\nTo learn more, run the command again \
                                     with --verbose.".to_string(), BLACK);
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
    debug!("handle_error; err={:?}", err);

    let _ignored_result = shell.error(err);
    handle_cause(err, shell);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if verbose != Verbose && !cargo_err.is_human() { return false }
        print(cargo_err.to_string(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if verbose != Verbose { return false }
        print(cause.to_string(), shell);
        err = cause.cause();
    }

    fn print(error: String, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", error), BLACK);
    }
}

pub fn version() -> VersionInfo {
    macro_rules! env_str {
        ($name:expr) => { env!($name).to_string() }
    }
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }
    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major: option_env_str!("CFG_VERSION_MAJOR").unwrap(),
                minor: option_env_str!("CFG_VERSION_MINOR").unwrap(),
                patch: option_env_str!("CFG_VERSION_PATCH").unwrap(),
                pre_release: option_env_str!("CFG_PRERELEASE_VERSION"),
                cfg_info: Some(CfgInfo {
                    build_date: option_env_str!("CFG_BUILD_DATE").unwrap(),
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info: commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major: env_str!("CARGO_PKG_VERSION_MAJOR"),
                minor: env_str!("CARGO_PKG_VERSION_MINOR"),
                patch: env_str!("CARGO_PKG_VERSION_PATCH"),
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<|endoftext|>