<commit_before>//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
//! are supplied to us before normalization and may contain opaque
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).

use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::ty::Ty;

use rustc_index::vec::Idx;
use rustc_span::Span;

use crate::borrow_check::universal_regions::UniversalRegions;

use super::{Locations, TypeChecker};

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
        body: &Body<'tcx>,
        universal_regions: &UniversalRegions<'tcx>,
        normalized_inputs_and_output: &[Ty<'tcx>],
    ) {
        let (&normalized_output_ty, normalized_input_tys) =
            normalized_inputs_and_output.split_last().unwrap();

        let mir_def_id = body.source.def_id().expect_local();

        // If the user explicitly annotated the input types, extract
        // those.
        //
        // e.g., `|x: FxHashMap<_, &'static u32>| ...`
        let user_provided_sig;
        if !self.tcx().is_closure(mir_def_id.to_def_id()) {
            user_provided_sig = None;
        } else {
            let typeck_results = self.tcx().typeck(mir_def_id);
            user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
                |user_provided_poly_sig| {
                    // Instantiate the canonicalized variables from
                    // user-provided signature (e.g., the `_` in the code
                    // above) with fresh variables.
                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
                        body.span,
                        &user_provided_poly_sig,
                    );

                    // Replace the bound items in the fn sig with fresh
                    // variables, so that they represent the view from
                    // "inside" the closure.
                    self.infcx
                        .replace_bound_vars_with_fresh_vars(
                            body.span,
                            LateBoundRegionConversionTime::FnCall,
                            poly_sig,
                        )
                        .0
                },
            );
        }

        debug!(
            "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
            normalized_input_tys, body.local_decls
        );

        // Equate expected input tys with those in the MIR.
        for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
            // In MIR, argument N is stored in local N+1.
            let local = Local::new(argument_index + 1);

            let mir_input_ty = body.local_decls[local].ty;
            let mir_input_span = body.local_decls[local].source_info.span;
            self.equate_normalized_input_or_output(
                normalized_input_ty,
                mir_input_ty,
                mir_input_span,
            );
        }

        if let Some(user_provided_sig) = user_provided_sig {
            for (argument_index, &user_provided_input_ty) in
                user_provided_sig.inputs().iter().enumerate()
            {
                // In MIR, closures begin an implicit `self`, so
                // argument N is stored in local N+2.
                let local = Local::new(argument_index + 2);
                let mir_input_ty = body.local_decls[local].ty;
                let mir_input_span = body.local_decls[local].source_info.span;

                // If the user explicitly annotated the input types, enforce those.
                let user_provided_input_ty =
                    self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
                self.equate_normalized_input_or_output(
                    user_provided_input_ty,
                    mir_input_ty,
                    mir_input_span,
                );
            }
        }

        assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
        if let Some(mir_yield_ty) = body.yield_ty() {
            let ur_yield_ty = universal_regions.yield_ty.unwrap();
            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
            self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
        }

        // Return types are a bit more complex. They may contain opaque `impl Trait` types.
        let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
        let output_span = body.local_decls[RETURN_PLACE].source_info.span;
        if let Err(terr) = self.eq_opaque_type_and_type(
            mir_output_ty,
            normalized_output_ty,
            mir_def_id,
            Locations::All(output_span),
            ConstraintCategory::BoringNoLocation,
        ) {
            span_mirbug!(
                self,
                Location::START,
                "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                normalized_output_ty,
                mir_output_ty,
                terr
            );
        };

        // If the user explicitly annotated the output types, enforce those.
        // Note that this only happens for closures.
        if let Some(user_provided_sig) = user_provided_sig {
            let user_provided_output_ty = user_provided_sig.output();
            let user_provided_output_ty =
                self.normalize(user_provided_output_ty, Locations::All(output_span));
            if let Err(err) = self.eq_opaque_type_and_type(
                mir_output_ty,
                user_provided_output_ty,
                mir_def_id,
                Locations::All(output_span),
                ConstraintCategory::BoringNoLocation,
            ) {
                span_mirbug!(
                    self,
                    Location::START,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    mir_output_ty,
                    user_provided_output_ty,
                    err
                );
            }
        }
    }

    fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

        if let Err(terr) =
            self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
        {
            span_mirbug!(
                self,
                Location::START,
                "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                a,
                b,
                terr
            );
        }
    }
}
<commit_msg>Break when there is a mismatch in the type count<commit_after>//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
//! are supplied to us before normalization and may contain opaque
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).

use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::ty::Ty;

use rustc_index::vec::Idx;
use rustc_span::Span;

use crate::borrow_check::universal_regions::UniversalRegions;

use super::{Locations, TypeChecker};

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
        body: &Body<'tcx>,
        universal_regions: &UniversalRegions<'tcx>,
        normalized_inputs_and_output: &[Ty<'tcx>],
    ) {
        let (&normalized_output_ty, normalized_input_tys) =
            normalized_inputs_and_output.split_last().unwrap();

        let mir_def_id = body.source.def_id().expect_local();

        // If the user explicitly annotated the input types, extract
        // those.
        //
        // e.g., `|x: FxHashMap<_, &'static u32>| ...`
        let user_provided_sig;
        if !self.tcx().is_closure(mir_def_id.to_def_id()) {
            user_provided_sig = None;
        } else {
            let typeck_results = self.tcx().typeck(mir_def_id);
            user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
                |user_provided_poly_sig| {
                    // Instantiate the canonicalized variables from
                    // user-provided signature (e.g., the `_` in the code
                    // above) with fresh variables.
                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
                        body.span,
                        &user_provided_poly_sig,
                    );

                    // Replace the bound items in the fn sig with fresh
                    // variables, so that they represent the view from
                    // "inside" the closure.
                    self.infcx
                        .replace_bound_vars_with_fresh_vars(
                            body.span,
                            LateBoundRegionConversionTime::FnCall,
                            poly_sig,
                        )
                        .0
                },
            );
        }

        debug!(
            "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
            normalized_input_tys, body.local_decls
        );

        // Equate expected input tys with those in the MIR.
        for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
            if argument_index + 1 >= body.local_decls.len() {
                self.tcx()
                    .sess
                    .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
                break;
            }
            // In MIR, argument N is stored in local N+1.
            let local = Local::new(argument_index + 1);

            let mir_input_ty = body.local_decls[local].ty;
            let mir_input_span = body.local_decls[local].source_info.span;
            self.equate_normalized_input_or_output(
                normalized_input_ty,
                mir_input_ty,
                mir_input_span,
            );
        }

        if let Some(user_provided_sig) = user_provided_sig {
            for (argument_index, &user_provided_input_ty) in
                user_provided_sig.inputs().iter().enumerate()
            {
                // In MIR, closures begin an implicit `self`, so
                // argument N is stored in local N+2.
                let local = Local::new(argument_index + 2);
                let mir_input_ty = body.local_decls[local].ty;
                let mir_input_span = body.local_decls[local].source_info.span;

                // If the user explicitly annotated the input types, enforce those.
                let user_provided_input_ty =
                    self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
                self.equate_normalized_input_or_output(
                    user_provided_input_ty,
                    mir_input_ty,
                    mir_input_span,
                );
            }
        }

        assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
        if let Some(mir_yield_ty) = body.yield_ty() {
            let ur_yield_ty = universal_regions.yield_ty.unwrap();
            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
            self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
        }

        // Return types are a bit more complex. They may contain opaque `impl Trait` types.
        let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
        let output_span = body.local_decls[RETURN_PLACE].source_info.span;
        if let Err(terr) = self.eq_opaque_type_and_type(
            mir_output_ty,
            normalized_output_ty,
            mir_def_id,
            Locations::All(output_span),
            ConstraintCategory::BoringNoLocation,
        ) {
            span_mirbug!(
                self,
                Location::START,
                "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                normalized_output_ty,
                mir_output_ty,
                terr
            );
        };

        // If the user explicitly annotated the output types, enforce those.
        // Note that this only happens for closures.
        if let Some(user_provided_sig) = user_provided_sig {
            let user_provided_output_ty = user_provided_sig.output();
            let user_provided_output_ty =
                self.normalize(user_provided_output_ty, Locations::All(output_span));
            if let Err(err) = self.eq_opaque_type_and_type(
                mir_output_ty,
                user_provided_output_ty,
                mir_def_id,
                Locations::All(output_span),
                ConstraintCategory::BoringNoLocation,
            ) {
                span_mirbug!(
                    self,
                    Location::START,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    mir_output_ty,
                    user_provided_output_ty,
                    err
                );
            }
        }
    }

    fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

        if let Err(terr) =
            self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
        {
            span_mirbug!(
                self,
                Location::START,
                "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                a,
                b,
                terr
            );
        }
    }
}
<|endoftext|>


<commit_before>use super::parse_module;

use core::semantic::ast::Node;

macro_rules! expr_test {
    ($name:ident, $code:expr) => {
        #[test]
        fn $name() {
            assert_eq!( parse_module($code)
                            .unwrap()[0]
                            .to_sexpr(0)
                      , $code)
        }
    }
}

expr_test!(test_basic_add, "(+ 1 2)");
expr_test!(test_basic_sub, "(- 3 4)");
expr_test!(test_basic_div, "(/ 5 6)");
expr_test!(test_basic_mul, "(* 1 2)");
expr_test!(test_nested_arith_1, "(+ 1 (- 2 3))");
expr_test!(test_nested_arith_2, "(* (+ 1 2) 3 4)");
expr_test!(test_nested_arith_3, "(+ (/ 1 2) (* 3 4))");

expr_test!(test_call_1, "(my_fn 1 2)");
expr_test!(test_call_2, "(my_fn (my_other_fn a_var a_different_var))");
expr_test!(test_call_3
  , "(my_fn (my_other_fn a_var a_different_var) VarWithUppercase Othervar)");
expr_test!(test_call_4
  , "(my_fn (my_other_fn a_var a_different_var) (another_fn a_var))");

expr_test!(test_call_ptr_1, "(my_fn a *b)");
expr_test!(test_call_ptr_2, "(my_fn *a *b)");
expr_test!(test_call_ptr_3, "(my_fn &a)");
expr_test!(test_call_ptr_4, "(my_fn a &b)");
expr_test!(test_call_ptr_5, "(my_fn &a &b)");
expr_test!(test_call_ptr_6, "(my_fn @a)");
expr_test!(test_call_ptr_7, "(my_fn a @b)");
expr_test!(test_call_ptr_8, "(my_fn @a @b)");

expr_test!(test_defsyntax_1,
"(define fac (\u{3bb} (\u{8594} int int)
\t((0) 1)
\t((n) (fac (- n 1))))\n)");

#[test]
fn test_defsyntax_sugar() {
    let string =
r#"(def fac (fn {int -> int}
    ((0) 1)
    ((n) (fac (- n 1)))))"#;
    assert_eq!( parse_module(string).unwrap()[0]
                                   .to_sexpr(0)
              , "(define fac (\u{3bb} (\u{2192} int int)
\t((0) 1)
\t((n) (fac (- n 1))))\n)" )
}
<commit_msg>Fix additiona; bug in parser tests (oops) The unit tests for the parser still expected incorrect Unicode code points.<commit_after>use super::parse_module;

use core::semantic::ast::Node;

macro_rules! expr_test {
    ($name:ident, $code:expr) => {
        #[test]
        fn $name() {
            assert_eq!( parse_module($code)
                            .unwrap()[0]
                            .to_sexpr(0)
                      , $code)
        }
    }
}

expr_test!(test_basic_add, "(+ 1 2)");
expr_test!(test_basic_sub, "(- 3 4)");
expr_test!(test_basic_div, "(/ 5 6)");
expr_test!(test_basic_mul, "(* 1 2)");
expr_test!(test_nested_arith_1, "(+ 1 (- 2 3))");
expr_test!(test_nested_arith_2, "(* (+ 1 2) 3 4)");
expr_test!(test_nested_arith_3, "(+ (/ 1 2) (* 3 4))");

expr_test!(test_call_1, "(my_fn 1 2)");
expr_test!(test_call_2, "(my_fn (my_other_fn a_var a_different_var))");
expr_test!(test_call_3
  , "(my_fn (my_other_fn a_var a_different_var) VarWithUppercase Othervar)");
expr_test!(test_call_4
  , "(my_fn (my_other_fn a_var a_different_var) (another_fn a_var))");

expr_test!(test_call_ptr_1, "(my_fn a *b)");
expr_test!(test_call_ptr_2, "(my_fn *a *b)");
expr_test!(test_call_ptr_3, "(my_fn &a)");
expr_test!(test_call_ptr_4, "(my_fn a &b)");
expr_test!(test_call_ptr_5, "(my_fn &a &b)");
expr_test!(test_call_ptr_6, "(my_fn @a)");
expr_test!(test_call_ptr_7, "(my_fn a @b)");
expr_test!(test_call_ptr_8, "(my_fn @a @b)");

expr_test!(test_defsyntax_1,
"(define fac (\u{3bb} (\u{2192} int int)
\t((0) 1)
\t((n) (fac (- n 1))))\n)");

#[test]
fn test_defsyntax_sugar() {
    let string =
r#"(def fac (fn {int -> int}
    ((0) 1)
    ((n) (fac (- n 1)))))"#;
    assert_eq!( parse_module(string).unwrap()[0]
                                   .to_sexpr(0)
              , "(define fac (\u{3bb} (\u{2192} int int)
\t((0) 1)
\t((n) (fac (- n 1))))\n)" )
}
<|endoftext|>


<commit_before>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate pkg_config;
extern crate wayland_scanner;

use std::{env, io, fs};
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    meson();
    let protocol_header_path =
        generate_protocol_headers().expect("Could not generate header files for wayland protocols");
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let mut builder = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?pixman_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        .clang_arg(format!("-I{}", protocol_header_path.to_str().unwrap()))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL");
    if cfg!(feature = "unstable-features") {
        builder = builder.clang_arg("-DWLR_USE_UNSTABLE");
    }
    let generated = builder.generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=xcb-xinput");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    link_optional_libs();

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path =
        PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
                                   .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/x11", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_backend_x11");
        println!("cargo:rustc-link-lib=static=wlr_render");
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    if Path::new("wlroots").exists() {
        meson::build("wlroots", build_path_str);
    } else {
        panic!("The `wlroots` submodule does not exist");
    }
}

/// Gets the unstable and stable protocols in /usr/share-wayland-protocols and
/// generates server headers for them.
///
/// The path to the folder with the generated headers is returned. It will
/// have two directories, `stable`, and `unstable`.
fn generate_protocol_headers() -> io::Result<PathBuf> {
    let output_dir_str = env::var("OUT_DIR").unwrap();
    let out_path: PathBuf = format!("{}/wayland-protocols", output_dir_str).into();
    fs::create_dir(&out_path).ok();
    let protocols_prefix = pkg_config::get_variable("wayland-protocols", "prefix").unwrap();
    let protocols = fs::read_dir(format!("{}/share/wayland-protocols/stable", protocols_prefix))?
        .chain(fs::read_dir(format!("{}/share/wayland-protocols/unstable", protocols_prefix))?);
    for entry in protocols {
        let entry = entry?;
        for entry in fs::read_dir(entry.path())? {
            let entry = entry?;
            let path = entry.path();
            let mut filename = entry.file_name().into_string().unwrap();
            if filename.ends_with(".xml") {
                let new_length = filename.len() - 4;
                filename.truncate(new_length);
            }
            filename.push_str("-protocol");
            Command::new("wayland-scanner").arg("server-header")
                                           .arg(path.clone())
                                           .arg(format!("{}/{}.h",
                                                        out_path.to_str().unwrap(),
                                                        filename))
                                           .status()
                                           .unwrap();
        }
    }
    Ok(out_path)
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[("./wlroots/protocol/server-decoration.xml", "server_decoration")];

    for protocol in protocols {
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_server_api.rs", protocol.1)),
                                         wayland_scanner::Side::Server);
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_client_api.rs", protocol.1)),
                                         wayland_scanner::Side::Client);
        wayland_scanner::generate_c_interfaces(protocol.0,
                                               output_dir.join(format!("{}_interfaces.rs",
                                                                       protocol.1)));
    }
}

fn link_optional_libs() {
    if cfg!(feature = "libcap") && pkg_config::probe_library("libcap").is_ok() {
        println!("cargo:rustc-link-lib=dylib=cap");
    }
    if cfg!(feature = "systemd") && pkg_config::probe_library("libsystemd").is_ok() {
        println!("cargo:rustc-link-lib=dylib=systemd");
    }
    if cfg!(feature = "elogind") && pkg_config::probe_library("elogind").is_ok() {
        println!("cargo:rustc-link-lib=dylib=elogind");
    }
    if pkg_config::probe_library("xcb-errors").is_ok() {
       println!("cargo:rustc-link-lib=dylib=xcb-errors");
    }
}
<commit_msg>Fixed warning about linking to xcb twice<commit_after>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate pkg_config;
extern crate wayland_scanner;

use std::{env, io, fs};
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    meson();
    let protocol_header_path =
        generate_protocol_headers().expect("Could not generate header files for wayland protocols");
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let mut builder = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?pixman_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        .clang_arg(format!("-I{}", protocol_header_path.to_str().unwrap()))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL");
    if cfg!(feature = "unstable-features") {
        builder = builder.clang_arg("-DWLR_USE_UNSTABLE");
    }
    let generated = builder.generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=xcb-xinput");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    link_optional_libs();

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path =
        PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
                                   .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/",
                 build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/x11", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_backend_x11");
        println!("cargo:rustc-link-lib=static=wlr_render");
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    if Path::new("wlroots").exists() {
        meson::build("wlroots", build_path_str);
    } else {
        panic!("The `wlroots` submodule does not exist");
    }
}

/// Gets the unstable and stable protocols in /usr/share-wayland-protocols and
/// generates server headers for them.
///
/// The path to the folder with the generated headers is returned. It will
/// have two directories, `stable`, and `unstable`.
fn generate_protocol_headers() -> io::Result<PathBuf> {
    let output_dir_str = env::var("OUT_DIR").unwrap();
    let out_path: PathBuf = format!("{}/wayland-protocols", output_dir_str).into();
    fs::create_dir(&out_path).ok();
    let protocols_prefix = pkg_config::get_variable("wayland-protocols", "prefix").unwrap();
    let protocols = fs::read_dir(format!("{}/share/wayland-protocols/stable", protocols_prefix))?
        .chain(fs::read_dir(format!("{}/share/wayland-protocols/unstable", protocols_prefix))?);
    for entry in protocols {
        let entry = entry?;
        for entry in fs::read_dir(entry.path())? {
            let entry = entry?;
            let path = entry.path();
            let mut filename = entry.file_name().into_string().unwrap();
            if filename.ends_with(".xml") {
                let new_length = filename.len() - 4;
                filename.truncate(new_length);
            }
            filename.push_str("-protocol");
            Command::new("wayland-scanner").arg("server-header")
                                           .arg(path.clone())
                                           .arg(format!("{}/{}.h",
                                                        out_path.to_str().unwrap(),
                                                        filename))
                                           .status()
                                           .unwrap();
        }
    }
    Ok(out_path)
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[("./wlroots/protocol/server-decoration.xml", "server_decoration")];

    for protocol in protocols {
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_server_api.rs", protocol.1)),
                                         wayland_scanner::Side::Server);
        wayland_scanner::generate_c_code(protocol.0,
                                         output_dir.join(format!("{}_client_api.rs", protocol.1)),
                                         wayland_scanner::Side::Client);
        wayland_scanner::generate_c_interfaces(protocol.0,
                                               output_dir.join(format!("{}_interfaces.rs",
                                                                       protocol.1)));
    }
}

fn link_optional_libs() {
    if cfg!(feature = "libcap") && pkg_config::probe_library("libcap").is_ok() {
        println!("cargo:rustc-link-lib=dylib=cap");
    }
    if cfg!(feature = "systemd") && pkg_config::probe_library("libsystemd").is_ok() {
        println!("cargo:rustc-link-lib=dylib=systemd");
    }
    if cfg!(feature = "elogind") && pkg_config::probe_library("elogind").is_ok() {
        println!("cargo:rustc-link-lib=dylib=elogind");
    }
    if pkg_config::probe_library("xcb-errors").is_ok() {
       println!("cargo:rustc-link-lib=dylib=xcb-errors");
    }
}
<|endoftext|>


<commit_before>use lopdf::Document;
use lopdf::Object;
use log::info;

#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};
use std::str::FromStr;

fn main() {
	env_logger::init();

	let app = App::new("PDF utility program using lopdf library")
		.version(crate_version!())
		.author(crate_authors!())
		.arg(Arg::with_name("input").short("i").long("input").value_name("input file").takes_value(true).global(true))
		.arg(Arg::with_name("output").short("o").long("output").value_name("output file").takes_value(true).global(true))
		.subcommand(
			SubCommand::with_name("process").about("Process PDF document with specified operations").arg(
				Arg::with_name("operations")
					.value_name("operations")
					.help("e.g. prune_objects delete_zero_length_streams renumber_objects")
					.takes_value(true)
					.multiple(true),
			),
		)
		.subcommand(SubCommand::with_name("compress").about("Compress PDF document"))
		.subcommand(SubCommand::with_name("decompress").about("Decompress PDF document"))
		.subcommand(
			SubCommand::with_name("delete_pages")
				.about("Delete pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_pages")
				.about("Extract pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("prune_objects").about("Prune unused objects"))
		.subcommand(
			SubCommand::with_name("delete_objects")
				.about("Delete objects")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_text")
				.about("Extract text")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("replace_text")
				.about("Replace text")
				.arg(Arg::with_name("text").value_name("page_number:old_text=>new_text").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_stream")
				.about("Extract stream content")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("print_streams").about("Print streams"))
		.subcommand(SubCommand::with_name("renumber_objects").about("Renumber objects"))
		.subcommand(SubCommand::with_name("delete_zero_length_streams").about("Delete zero length stream objects"))
		.get_matches();

	if let (cmd, Some(args)) = app.subcommand() {
		if let Some(input) = args.value_of("input") {
			info!("Open {}", input);
			let mut doc = Document::load(input).unwrap();
			//info!("{:?}", doc.get_pages());

			info!("Do {}", cmd);
			match cmd {
				"process" => {
					if let Some(operations) = args.values_of("operations") {
						for operation in operations {
							info!("Do {}", operation);
							apply_operation(&mut doc, operation);
						}
					}
				}
				"extract_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let total = *doc.get_pages().keys().max().unwrap_or(&0);
						let page_numbers = complement_page_numbers(&page_numbers, total);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_objects" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.delete_object(&(nums[0], 0)),
								2 => doc.delete_object(&(nums[0], nums[1] as u16)),
								_ => None,
							};
						}
					}
				}
				"extract_text" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let text = doc.extract_text(&page_numbers);
						info!("{}", text);
					}
				}
				"replace_text" => {
					if let Some(text) = args.value_of("text") {
						let parts: Vec<&str> = text.splitn(2, ':').collect();
						let page = u32::from_str(parts[0]).unwrap();
						let words: Vec<&str> = parts[1].splitn(2, "=>").collect();
						doc.replace_text(page, words[0], words[1]);
					}
				}
				"print_streams" => for (_, object) in doc.objects.iter() {
					match *object {
						Object::Stream(ref stream) => info!("{:?}", stream.dict),
						_ => (),
					}
				},
				"extract_stream" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.extract_stream((nums[0], 0), false).ok(),
								2 => doc.extract_stream((nums[0], nums[1] as u16), false).ok(),
								_ => None,
							};
						}
					}
				}
				operation @ _ => {
					apply_operation(&mut doc, operation);
				}
			}

			doc.change_producer("https://crates.io/crates/lopdf");

			if let Some(output) = args.value_of("output") {
				info!("Save to {}", output);
				doc.save(output).unwrap();
			}
		}
	}

	fn apply_operation(doc: &mut Document, operation: &str) {
		match operation {
			"compress" => doc.compress(),
			"decompress" => doc.decompress(),
			"renumber_objects" => doc.renumber_objects(),
			"prune_objects" => {
				let ids = doc.prune_objects();
				info!("Deleted {:?}", ids);
			}
			"delete_zero_length_streams" => {
				let streams = doc.delete_zero_length_streams();
				if streams.len() > 0 {
					info!("Deleted {:?}", streams);
				}
			}
			_ => {}
		}
	}

	fn compute_page_numbers(pages: &str) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in pages.split(',') {
			let nums: Vec<u32> = page.split('-').map(|num| u32::from_str(num).unwrap()).collect();
			match nums.len() {
				1 => page_numbers.push(nums[0]),
				2 => page_numbers.append(&mut (nums[0]..nums[1] + 1).collect()),
				_ => {}
			}
		}
		page_numbers
	}

	fn complement_page_numbers(pages: &[u32], total: u32) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in 1..(total + 1) {
			if !pages.contains(&page) {
				page_numbers.push(page);
			}
		}
		page_numbers
	}
}
<commit_msg>Fix pdfutil build<commit_after>use lopdf::Document;
use lopdf::Object;
use log::info;

#[macro_use]
extern crate clap;
use clap::{App, Arg, SubCommand};
use std::str::FromStr;

fn main() {
	env_logger::init();

	let app = App::new("PDF utility program using lopdf library")
		.version(crate_version!())
		.author(crate_authors!())
		.arg(Arg::with_name("input").short("i").long("input").value_name("input file").takes_value(true).global(true))
		.arg(Arg::with_name("output").short("o").long("output").value_name("output file").takes_value(true).global(true))
		.subcommand(
			SubCommand::with_name("process").about("Process PDF document with specified operations").arg(
				Arg::with_name("operations")
					.value_name("operations")
					.help("e.g. prune_objects delete_zero_length_streams renumber_objects")
					.takes_value(true)
					.multiple(true),
			),
		)
		.subcommand(SubCommand::with_name("compress").about("Compress PDF document"))
		.subcommand(SubCommand::with_name("decompress").about("Decompress PDF document"))
		.subcommand(
			SubCommand::with_name("delete_pages")
				.about("Delete pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_pages")
				.about("Extract pages")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("prune_objects").about("Prune unused objects"))
		.subcommand(
			SubCommand::with_name("delete_objects")
				.about("Delete objects")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_text")
				.about("Extract text")
				.arg(Arg::with_name("pages").value_name("page numbers").help("e.g. 3,5,7-9").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("replace_text")
				.about("Replace text")
				.arg(Arg::with_name("text").value_name("page_number:old_text=>new_text").takes_value(true)),
		)
		.subcommand(
			SubCommand::with_name("extract_stream")
				.about("Extract stream content")
				.arg(Arg::with_name("ids").value_name("object ids").help("e.g. \"1 0,2 1,35,36\"").takes_value(true)),
		)
		.subcommand(SubCommand::with_name("print_streams").about("Print streams"))
		.subcommand(SubCommand::with_name("renumber_objects").about("Renumber objects"))
		.subcommand(SubCommand::with_name("delete_zero_length_streams").about("Delete zero length stream objects"))
		.get_matches();

	if let (cmd, Some(args)) = app.subcommand() {
		if let Some(input) = args.value_of("input") {
			info!("Open {}", input);
			let mut doc = Document::load(input).unwrap();
			//info!("{:?}", doc.get_pages());

			info!("Do {}", cmd);
			match cmd {
				"process" => {
					if let Some(operations) = args.values_of("operations") {
						for operation in operations {
							info!("Do {}", operation);
							apply_operation(&mut doc, operation);
						}
					}
				}
				"extract_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let total = *doc.get_pages().keys().max().unwrap_or(&0);
						let page_numbers = complement_page_numbers(&page_numbers, total);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_pages" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						doc.delete_pages(&page_numbers);
					}
				}
				"delete_objects" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.delete_object((nums[0], 0)),
								2 => doc.delete_object((nums[0], nums[1] as u16)),
								_ => None,
							};
						}
					}
				}
				"extract_text" => {
					if let Some(pages) = args.value_of("pages") {
						let page_numbers = compute_page_numbers(pages);
						let text = doc.extract_text(&page_numbers);
						info!("{}", text);
					}
				}
				"replace_text" => {
					if let Some(text) = args.value_of("text") {
						let parts: Vec<&str> = text.splitn(2, ':').collect();
						let page = u32::from_str(parts[0]).unwrap();
						let words: Vec<&str> = parts[1].splitn(2, "=>").collect();
						doc.replace_text(page, words[0], words[1]);
					}
				}
				"print_streams" => for (_, object) in doc.objects.iter() {
					match *object {
						Object::Stream(ref stream) => info!("{:?}", stream.dict),
						_ => (),
					}
				},
				"extract_stream" => {
					if let Some(ids) = args.value_of("ids") {
						for id in ids.split(',') {
							let nums: Vec<u32> = id.split(' ').map(|num| u32::from_str(num).unwrap()).collect();
							match nums.len() {
								1 => doc.extract_stream((nums[0], 0), false).ok(),
								2 => doc.extract_stream((nums[0], nums[1] as u16), false).ok(),
								_ => None,
							};
						}
					}
				}
				operation @ _ => {
					apply_operation(&mut doc, operation);
				}
			}

			doc.change_producer("https://crates.io/crates/lopdf");

			if let Some(output) = args.value_of("output") {
				info!("Save to {}", output);
				doc.save(output).unwrap();
			}
		}
	}

	fn apply_operation(doc: &mut Document, operation: &str) {
		match operation {
			"compress" => doc.compress(),
			"decompress" => doc.decompress(),
			"renumber_objects" => doc.renumber_objects(),
			"prune_objects" => {
				let ids = doc.prune_objects();
				info!("Deleted {:?}", ids);
			}
			"delete_zero_length_streams" => {
				let streams = doc.delete_zero_length_streams();
				if streams.len() > 0 {
					info!("Deleted {:?}", streams);
				}
			}
			_ => {}
		}
	}

	fn compute_page_numbers(pages: &str) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in pages.split(',') {
			let nums: Vec<u32> = page.split('-').map(|num| u32::from_str(num).unwrap()).collect();
			match nums.len() {
				1 => page_numbers.push(nums[0]),
				2 => page_numbers.append(&mut (nums[0]..nums[1] + 1).collect()),
				_ => {}
			}
		}
		page_numbers
	}

	fn complement_page_numbers(pages: &[u32], total: u32) -> Vec<u32> {
		let mut page_numbers = vec![];
		for page in 1..(total + 1) {
			if !pages.contains(&page) {
				page_numbers.push(page);
			}
		}
		page_numbers
	}
}
<|endoftext|>


<commit_before>use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
use gio;
use markup5ever::{LocalName, Namespace, QualName};
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::rc::Rc;

use crate::allowed_url::{AllowedUrl, Fragment};
use crate::create_node::create_node;
use crate::css::Stylesheet;
use crate::error::LoadingError;
use crate::handle::LoadOptions;
use crate::io::{self, BinaryData};
use crate::node::{NodeCascade, NodeData, NodeType, RsvgNode};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::structure::{IntrinsicDimensions, Svg};
use crate::surface_utils::shared_surface::SharedImageSurface;
use crate::text::NodeChars;
use crate::xml::xml_load_from_possibly_compressed_stream;

/// A loaded SVG file and its derived data
///
/// This contains the tree of nodes (SVG elements), the mapping
/// of id to node, and the CSS styles defined for this SVG.
pub struct Document {
    tree: RsvgNode,

    ids: HashMap<String, RsvgNode>,

    // These require interior mutability because we load the extern
    // resources all over the place.  Eventually we'll be able to do this
    // once, at loading time, and keep this immutable.
    externs: RefCell<Resources>,
    images: RefCell<Images>,

    // Once we do not need to load externs, we can drop this as well
    load_options: LoadOptions,
}

impl Document {
    pub fn load_from_stream(
        load_options: &LoadOptions,
        stream: &gio::InputStream,
        cancellable: Option<&gio::Cancellable>,
    ) -> Result<Document, LoadingError> {
        xml_load_from_possibly_compressed_stream(
            DocumentBuilder::new(load_options),
            load_options.unlimited_size,
            stream,
            cancellable,
        )
    }

    pub fn root(&self) -> RsvgNode {
        self.tree.clone()
    }

    pub fn lookup(&self, fragment: &Fragment) -> Result<RsvgNode, LoadingError> {
        if fragment.uri().is_some() {
            self.externs
                .borrow_mut()
                .lookup(&self.load_options, fragment)
        } else {
            self.lookup_node_by_id(fragment.fragment())
                .ok_or(LoadingError::BadUrl)
        }
    }

    pub fn lookup_node_by_id(&self, id: &str) -> Option<RsvgNode> {
        self.ids.get(id).map(|n| (*n).clone())
    }

    pub fn lookup_image(&self, href: &str) -> Result<SharedImageSurface, LoadingError> {
        self.images.borrow_mut().lookup(&self.load_options, href)
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        let root = self.root();
        let node_data = root.borrow();

        assert!(node_data.get_type() == NodeType::Svg);
        node_data.get_impl::<Svg>().get_intrinsic_dimensions()
    }
}

struct Resources {
    resources: HashMap<AllowedUrl, Result<Rc<Document>, LoadingError>>,
}

impl Resources {
    pub fn new() -> Resources {
        Resources {
            resources: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        fragment: &Fragment,
    ) -> Result<RsvgNode, LoadingError> {
        if let Some(ref href) = fragment.uri() {
            self.get_extern_document(load_options, href)
                .and_then(|doc| {
                    doc.lookup_node_by_id(fragment.fragment())
                        .ok_or(LoadingError::BadUrl)
                })
        } else {
            unreachable!();
        }
    }

    fn get_extern_document(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<Rc<Document>, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.resources.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let aurl = e.key();
                // FIXME: pass a cancellable to these
                let doc = io::acquire_stream(aurl, None)
                    .and_then(|stream| {
                        Document::load_from_stream(
                            &load_options.copy_with_base_url(aurl),
                            &stream,
                            None,
                        )
                    })
                    .map(Rc::new);
                let res = e.insert(doc);
                res.clone()
            }
        }
    }
}

struct Images {
    images: HashMap<AllowedUrl, Result<SharedImageSurface, LoadingError>>,
}

impl Images {
    pub fn new() -> Images {
        Images {
            images: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<SharedImageSurface, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.images.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let surface = load_image(load_options, e.key());
                let res = e.insert(surface);
                res.clone()
            }
        }
    }
}

fn load_image(
    load_options: &LoadOptions,
    aurl: &AllowedUrl,
) -> Result<SharedImageSurface, LoadingError> {
    let BinaryData {
        data: bytes,
        content_type,
    } = io::acquire_data(&aurl, None)?;

    if bytes.is_empty() {
        return Err(LoadingError::EmptyData);
    }

    let loader = if let Some(ref content_type) = content_type {
        PixbufLoader::new_with_mime_type(content_type)?
    } else {
        PixbufLoader::new()
    };

    loader.write(&bytes)?;
    loader.close()?;

    let pixbuf = loader.get_pixbuf().ok_or(LoadingError::Unknown)?;

    let bytes = if load_options.keep_image_data {
        Some(bytes)
    } else {
        None
    };

    let surface =
        SharedImageSurface::from_pixbuf(&pixbuf, bytes, content_type.as_ref().map(String::as_str))?;

    Ok(surface)
}

pub struct DocumentBuilder {
    load_options: LoadOptions,
    tree: Option<RsvgNode>,
    ids: HashMap<String, RsvgNode>,
    stylesheets: Vec<Stylesheet>,
}

impl DocumentBuilder {
    pub fn new(load_options: &LoadOptions) -> DocumentBuilder {
        DocumentBuilder {
            load_options: load_options.clone(),
            tree: None,
            ids: HashMap::new(),
            stylesheets: Vec::new(),
        }
    }

    pub fn append_stylesheet_from_xml_processing_instruction(
        &mut self,
        alternate: Option<String>,
        type_: Option<String>,
        href: &str,
    ) -> Result<(), LoadingError> {
        if type_.as_ref().map(String::as_str) != Some("text/css")
            || (alternate.is_some() && alternate.as_ref().map(String::as_str) != Some("no"))
        {
            return Err(LoadingError::BadStylesheet);
        }

        // FIXME: handle CSS errors
        if let Ok(stylesheet) = Stylesheet::from_href(href, self.load_options.base_url.as_ref()) {
            self.stylesheets.push(stylesheet);
        }

        Ok(())
    }

    pub fn append_element(
        &mut self,
        name: &QualName,
        pbag: &PropertyBag,
        parent: Option<RsvgNode>,
    ) -> RsvgNode {
        let mut node = create_node(name, pbag);

        if let Some(id) = node.borrow().get_id() {
            // This is so we don't overwrite an existing id
            self.ids
                .entry(id.to_string())
                .or_insert_with(|| node.clone());
        }

        node.borrow_mut()
            .set_atts(parent.as_ref().clone(), pbag, self.load_options.locale());

        if let Some(mut parent) = parent {
            parent.append(node.clone());
        } else if self.tree.is_none() {
            self.tree = Some(node.clone());
        } else {
            panic!("The tree root has already been set");
        }

        node
    }

    pub fn append_stylesheet_from_text(&mut self, text: &str) {
        // FIXME: handle CSS errors
        if let Ok(stylesheet) = Stylesheet::from_data(text, self.load_options.base_url.as_ref()) {
            self.stylesheets.push(stylesheet);
        }
    }

    pub fn append_characters(&mut self, text: &str, parent: &mut RsvgNode) {
        if !text.is_empty() {
            self.append_chars_to_parent(text, parent);
        }
    }

    fn append_chars_to_parent(&mut self, text: &str, parent: &mut RsvgNode) {
        // When the last child is a Chars node we can coalesce
        // the text and avoid screwing up the Pango layouts
        let chars_node = if let Some(child) = parent
            .last_child()
            .filter(|c| c.borrow().get_type() == NodeType::Chars)
        {
            child
        } else {
            let child = RsvgNode::new(NodeData::new(
                NodeType::Chars,
                &QualName::new(
                    None,
                    Namespace::from("https://wiki.gnome.org/Projects/LibRsvg"),
                    LocalName::from("rsvg-chars"),
                ),
                None,
                None,
                Box::new(NodeChars::new()),
            ));

            parent.append(child.clone());

            child
        };

        chars_node.borrow().get_impl::<NodeChars>().append(text);
    }

    pub fn resolve_href(&self, href: &str) -> Result<AllowedUrl, LoadingError> {
        AllowedUrl::from_href(href, self.load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)
    }

    pub fn build(self) -> Result<Document, LoadingError> {
        let DocumentBuilder { load_options, tree, ids, stylesheets, .. } = self;

        match tree {
            None => Err(LoadingError::SvgHasNoElements),
            Some(mut root) => {
                if root.borrow().get_type() == NodeType::Svg {
                    for mut node in root.descendants() {
                        for stylesheet in &stylesheets {
                            stylesheet.apply_matches_to_node(&mut node);
                        }

                        node.borrow_mut().set_style_attribute();
                    }

                    let values = ComputedValues::default();
                    root.cascade(&values);

                    Ok(Document {
                        tree: root.clone(),
                        ids,
                        externs: RefCell::new(Resources::new()),
                        images: RefCell::new(Images::new()),
                        load_options: load_options.clone(),
                    })
                } else {
                    Err(LoadingError::RootElementIsNotSvg)
                }
            }
        }
    }
}
<commit_msg>document: remove uneeded map_err<commit_after>use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
use gio;
use markup5ever::{LocalName, Namespace, QualName};
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::rc::Rc;

use crate::allowed_url::{AllowedUrl, AllowedUrlError, Fragment};
use crate::create_node::create_node;
use crate::css::Stylesheet;
use crate::error::LoadingError;
use crate::handle::LoadOptions;
use crate::io::{self, BinaryData};
use crate::node::{NodeCascade, NodeData, NodeType, RsvgNode};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::structure::{IntrinsicDimensions, Svg};
use crate::surface_utils::shared_surface::SharedImageSurface;
use crate::text::NodeChars;
use crate::xml::xml_load_from_possibly_compressed_stream;

/// A loaded SVG file and its derived data
///
/// This contains the tree of nodes (SVG elements), the mapping
/// of id to node, and the CSS styles defined for this SVG.
pub struct Document {
    tree: RsvgNode,

    ids: HashMap<String, RsvgNode>,

    // These require interior mutability because we load the extern
    // resources all over the place.  Eventually we'll be able to do this
    // once, at loading time, and keep this immutable.
    externs: RefCell<Resources>,
    images: RefCell<Images>,

    // Once we do not need to load externs, we can drop this as well
    load_options: LoadOptions,
}

impl Document {
    pub fn load_from_stream(
        load_options: &LoadOptions,
        stream: &gio::InputStream,
        cancellable: Option<&gio::Cancellable>,
    ) -> Result<Document, LoadingError> {
        xml_load_from_possibly_compressed_stream(
            DocumentBuilder::new(load_options),
            load_options.unlimited_size,
            stream,
            cancellable,
        )
    }

    pub fn root(&self) -> RsvgNode {
        self.tree.clone()
    }

    pub fn lookup(&self, fragment: &Fragment) -> Result<RsvgNode, LoadingError> {
        if fragment.uri().is_some() {
            self.externs
                .borrow_mut()
                .lookup(&self.load_options, fragment)
        } else {
            self.lookup_node_by_id(fragment.fragment())
                .ok_or(LoadingError::BadUrl)
        }
    }

    pub fn lookup_node_by_id(&self, id: &str) -> Option<RsvgNode> {
        self.ids.get(id).map(|n| (*n).clone())
    }

    pub fn lookup_image(&self, href: &str) -> Result<SharedImageSurface, LoadingError> {
        self.images.borrow_mut().lookup(&self.load_options, href)
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        let root = self.root();
        let node_data = root.borrow();

        assert!(node_data.get_type() == NodeType::Svg);
        node_data.get_impl::<Svg>().get_intrinsic_dimensions()
    }
}

struct Resources {
    resources: HashMap<AllowedUrl, Result<Rc<Document>, LoadingError>>,
}

impl Resources {
    pub fn new() -> Resources {
        Resources {
            resources: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        fragment: &Fragment,
    ) -> Result<RsvgNode, LoadingError> {
        if let Some(ref href) = fragment.uri() {
            self.get_extern_document(load_options, href)
                .and_then(|doc| {
                    doc.lookup_node_by_id(fragment.fragment())
                        .ok_or(LoadingError::BadUrl)
                })
        } else {
            unreachable!();
        }
    }

    fn get_extern_document(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<Rc<Document>, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.resources.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let aurl = e.key();
                // FIXME: pass a cancellable to these
                let doc = io::acquire_stream(aurl, None)
                    .and_then(|stream| {
                        Document::load_from_stream(
                            &load_options.copy_with_base_url(aurl),
                            &stream,
                            None,
                        )
                    })
                    .map(Rc::new);
                let res = e.insert(doc);
                res.clone()
            }
        }
    }
}

struct Images {
    images: HashMap<AllowedUrl, Result<SharedImageSurface, LoadingError>>,
}

impl Images {
    pub fn new() -> Images {
        Images {
            images: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<SharedImageSurface, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.images.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let surface = load_image(load_options, e.key());
                let res = e.insert(surface);
                res.clone()
            }
        }
    }
}

fn load_image(
    load_options: &LoadOptions,
    aurl: &AllowedUrl,
) -> Result<SharedImageSurface, LoadingError> {
    let BinaryData {
        data: bytes,
        content_type,
    } = io::acquire_data(&aurl, None)?;

    if bytes.is_empty() {
        return Err(LoadingError::EmptyData);
    }

    let loader = if let Some(ref content_type) = content_type {
        PixbufLoader::new_with_mime_type(content_type)?
    } else {
        PixbufLoader::new()
    };

    loader.write(&bytes)?;
    loader.close()?;

    let pixbuf = loader.get_pixbuf().ok_or(LoadingError::Unknown)?;

    let bytes = if load_options.keep_image_data {
        Some(bytes)
    } else {
        None
    };

    let surface =
        SharedImageSurface::from_pixbuf(&pixbuf, bytes, content_type.as_ref().map(String::as_str))?;

    Ok(surface)
}

pub struct DocumentBuilder {
    load_options: LoadOptions,
    tree: Option<RsvgNode>,
    ids: HashMap<String, RsvgNode>,
    stylesheets: Vec<Stylesheet>,
}

impl DocumentBuilder {
    pub fn new(load_options: &LoadOptions) -> DocumentBuilder {
        DocumentBuilder {
            load_options: load_options.clone(),
            tree: None,
            ids: HashMap::new(),
            stylesheets: Vec::new(),
        }
    }

    pub fn append_stylesheet_from_xml_processing_instruction(
        &mut self,
        alternate: Option<String>,
        type_: Option<String>,
        href: &str,
    ) -> Result<(), LoadingError> {
        if type_.as_ref().map(String::as_str) != Some("text/css")
            || (alternate.is_some() && alternate.as_ref().map(String::as_str) != Some("no"))
        {
            return Err(LoadingError::BadStylesheet);
        }

        // FIXME: handle CSS errors
        if let Ok(stylesheet) = Stylesheet::from_href(href, self.load_options.base_url.as_ref()) {
            self.stylesheets.push(stylesheet);
        }

        Ok(())
    }

    pub fn append_element(
        &mut self,
        name: &QualName,
        pbag: &PropertyBag,
        parent: Option<RsvgNode>,
    ) -> RsvgNode {
        let mut node = create_node(name, pbag);

        if let Some(id) = node.borrow().get_id() {
            // This is so we don't overwrite an existing id
            self.ids
                .entry(id.to_string())
                .or_insert_with(|| node.clone());
        }

        node.borrow_mut()
            .set_atts(parent.as_ref().clone(), pbag, self.load_options.locale());

        if let Some(mut parent) = parent {
            parent.append(node.clone());
        } else if self.tree.is_none() {
            self.tree = Some(node.clone());
        } else {
            panic!("The tree root has already been set");
        }

        node
    }

    pub fn append_stylesheet_from_text(&mut self, text: &str) {
        // FIXME: handle CSS errors
        if let Ok(stylesheet) = Stylesheet::from_data(text, self.load_options.base_url.as_ref()) {
            self.stylesheets.push(stylesheet);
        }
    }

    pub fn append_characters(&mut self, text: &str, parent: &mut RsvgNode) {
        if !text.is_empty() {
            self.append_chars_to_parent(text, parent);
        }
    }

    fn append_chars_to_parent(&mut self, text: &str, parent: &mut RsvgNode) {
        // When the last child is a Chars node we can coalesce
        // the text and avoid screwing up the Pango layouts
        let chars_node = if let Some(child) = parent
            .last_child()
            .filter(|c| c.borrow().get_type() == NodeType::Chars)
        {
            child
        } else {
            let child = RsvgNode::new(NodeData::new(
                NodeType::Chars,
                &QualName::new(
                    None,
                    Namespace::from("https://wiki.gnome.org/Projects/LibRsvg"),
                    LocalName::from("rsvg-chars"),
                ),
                None,
                None,
                Box::new(NodeChars::new()),
            ));

            parent.append(child.clone());

            child
        };

        chars_node.borrow().get_impl::<NodeChars>().append(text);
    }

    pub fn resolve_href(&self, href: &str) -> Result<AllowedUrl, AllowedUrlError> {
        AllowedUrl::from_href(href, self.load_options.base_url.as_ref())
    }

    pub fn build(self) -> Result<Document, LoadingError> {
        let DocumentBuilder { load_options, tree, ids, stylesheets, .. } = self;

        match tree {
            None => Err(LoadingError::SvgHasNoElements),
            Some(mut root) => {
                if root.borrow().get_type() == NodeType::Svg {
                    for mut node in root.descendants() {
                        for stylesheet in &stylesheets {
                            stylesheet.apply_matches_to_node(&mut node);
                        }

                        node.borrow_mut().set_style_attribute();
                    }

                    let values = ComputedValues::default();
                    root.cascade(&values);

                    Ok(Document {
                        tree: root.clone(),
                        ids,
                        externs: RefCell::new(Resources::new()),
                        images: RefCell::new(Images::new()),
                        load_options: load_options.clone(),
                    })
                } else {
                    Err(LoadingError::RootElementIsNotSvg)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#![deny(invalid_upcast_comparisons)]
#![allow(unused, eq_op, no_effect)]
fn main() {
    let zero: u32 = 0;
    let u8_max: u8 = 255;

    (u8_max as u32) > 300; //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false
    (u8_max as u32) > 20;

    (zero as i32) < -5; //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false
    (zero as i32) < 10;

    -5 < (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always true
    0 <= (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always true
    0 < (zero as i32);

    -5 > (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false
    -5 >= (u8_max as i32); //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false
}
<commit_msg>Added tests for eq and neq invalid upcast comparisons<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#![deny(invalid_upcast_comparisons)]
#![allow(unused, eq_op, no_effect)]
fn main() {
    let zero: u32 = 0;
    let u8_max: u8 = 255;

    (u8_max as u32) > 300; //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false
    (u8_max as u32) > 20;

    (zero as i32) < -5; //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false
    (zero as i32) < 10;

    -5 < (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always true
    0 <= (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always true
    0 < (zero as i32);

    -5 > (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false
    -5 >= (u8_max as i32); //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always false

    -5 == (zero as i32); //~ERROR because of the numeric bounds on `zero` prior to casting, this expression is always false
    -5 != (u8_max as i32); //~ERROR because of the numeric bounds on `u8_max` prior to casting, this expression is always true
}
<|endoftext|>


<commit_before>// Copyright 2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rand;
extern crate ndarray;

use std::iter::FromIterator;

use rand::Rng;
use rand::distributions::Sample;
use rand::distributions::IndependentSample;

use ndarray::{
    ArrayBase,
    Dimension,
    DataOwned,
};

/// Constructors for n-dimensional arrays with random elements.
///
/// This trait extends ndarray’s `ArrayBase` and can not be implemented
/// for other types.
///
/// The default Rng is a fast automatically seeded rng (currently `rand::weak_rng`).
pub trait RandomExt<S, D>
    where S: DataOwned,
          D: Dimension,
{
    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`  using the default rng.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    ///
    /// ```
    /// extern crate rand;
    /// extern crate ndarray;
    /// extern crate ndarray_rand;
    ///
    /// use rand::distributions::Range;
    /// use ndarray::OwnedArray;
    /// use ndarray_rand::RandomExt;
    ///
    /// # fn main() {
    /// let a = OwnedArray::random((2, 5), Range::new(0., 10.));
    /// println!("{:8.4}", a);
    /// // Output:
    /// // [[  8.6900,   6.9824,   3.8922,   6.5861,   2.4890],
    /// //  [  0.0914,   5.5186,   5.8135,   5.2361,   3.1879]]
    /// # }
    fn random<IdS>(dim: D, distribution: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>;

    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`, using a specific Rng `rng`.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    fn random_using<IdS, R>(dim: D, distribution: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng;
}

impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
    where S: DataOwned,
          D: Dimension,
{
    fn random<IdS>(dim: D, dist: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>
    {
        Self::random_using(dim, dist, &mut rand::weak_rng())
    }

    fn random_using<IdS, R>(dim: D, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng
    {
        let elements = Vec::from_iter((0..dim.size()).map(move |_| dist.ind_sample(rng)));
        Self::from_vec_dim(dim, elements).unwrap()
    }
}

/// A wrapper type that allows casting f64 distributions to f32
#[derive(Copy, Clone, Debug)]
pub struct F32<S>(pub S);

impl<S> Sample<f32> for F32<S>
    where S: Sample<f64>
{
    fn sample<R>(&mut self, rng: &mut R) -> f32 where R: Rng {
        self.0.sample(rng) as f32
    }
}

impl<S> IndependentSample<f32> for F32<S>
    where S: IndependentSample<f64>
{
    fn ind_sample<R>(&self, rng: &mut R) -> f32 where R: Rng {
        self.0.ind_sample(rng) as f32
    }
}
<commit_msg>ndarray-rand: Add example to F32<commit_after>// Copyright 2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rand;
extern crate ndarray;

use std::iter::FromIterator;

use rand::Rng;
use rand::distributions::Sample;
use rand::distributions::IndependentSample;

use ndarray::{
    ArrayBase,
    Dimension,
    DataOwned,
};

/// Constructors for n-dimensional arrays with random elements.
///
/// This trait extends ndarray’s `ArrayBase` and can not be implemented
/// for other types.
///
/// The default Rng is a fast automatically seeded rng (currently `rand::weak_rng`).
pub trait RandomExt<S, D>
    where S: DataOwned,
          D: Dimension,
{
    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`  using the default rng.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    ///
    /// ```
    /// extern crate rand;
    /// extern crate ndarray;
    /// extern crate ndarray_rand;
    ///
    /// use rand::distributions::Range;
    /// use ndarray::OwnedArray;
    /// use ndarray_rand::RandomExt;
    ///
    /// # fn main() {
    /// let a = OwnedArray::random((2, 5), Range::new(0., 10.));
    /// println!("{:8.4}", a);
    /// // Example Output:
    /// // [[  8.6900,   6.9824,   3.8922,   6.5861,   2.4890],
    /// //  [  0.0914,   5.5186,   5.8135,   5.2361,   3.1879]]
    /// # }
    fn random<IdS>(dim: D, distribution: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>;

    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`, using a specific Rng `rng`.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    fn random_using<IdS, R>(dim: D, distribution: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng;
}

impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
    where S: DataOwned,
          D: Dimension,
{
    fn random<IdS>(dim: D, dist: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>
    {
        Self::random_using(dim, dist, &mut rand::weak_rng())
    }

    fn random_using<IdS, R>(dim: D, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng
    {
        let elements = Vec::from_iter((0..dim.size()).map(move |_| dist.ind_sample(rng)));
        Self::from_vec_dim(dim, elements).unwrap()
    }
}

/// A wrapper type that allows casting f64 distributions to f32
///
/// ```
/// extern crate rand;
/// extern crate ndarray;
/// extern crate ndarray_rand;
///
/// use rand::distributions::Normal;
/// use ndarray::OwnedArray;
/// use ndarray_rand::{RandomExt, F32};
///
/// # fn main() {
/// let a = OwnedArray::random((2, 5), F32(Normal::new(0., 1.)));
/// println!("{:8.4}", a);
/// // Example Output:
/// // [[ -0.6910,   1.1730,   1.0902,  -0.4092,  -1.7340],
/// //  [ -0.6810,   0.1678,  -0.9487,   0.3150,   1.2981]]
/// # }
#[derive(Copy, Clone, Debug)]
pub struct F32<S>(pub S);

impl<S> Sample<f32> for F32<S>
    where S: Sample<f64>
{
    fn sample<R>(&mut self, rng: &mut R) -> f32 where R: Rng {
        self.0.sample(rng) as f32
    }
}

impl<S> IndependentSample<f32> for F32<S>
    where S: IndependentSample<f64>
{
    fn ind_sample<R>(&self, rng: &mut R) -> f32 where R: Rng {
        self.0.ind_sample(rng) as f32
    }
}
<|endoftext|>


<commit_before>//! Physical memory management

use alloc::boxed::Box;

use core::ops::{Index, IndexMut};

use interrupts::{no_interrupts, off, on};
use process::CURRENT_PROCESS;
use static_linked_list::StaticLinkedList;

use super::regionmap::RegionMap;

/// Array of `FrameInfo`. This is a pointer to the region of memory used
/// to hold physical memory allocation metadata.
static mut FRAME_INFO: *mut FrameInfoSection = 0 as *mut FrameInfoSection;

/// The index of the first free frame in a LIFO list.
/// 0 => empty list
static mut FREE_FRAMES: usize = 0;

/// A physical memory frame
#[repr(C, packed)]
pub struct Frame([usize; 1024]);

/// Should take up 4MiB on a 32-bit machine.
/// There is one frame info for each frame, associated by frame index
#[repr(C, packed)]
pub struct FrameInfoSection([FrameInfo; 1 << 20]);

/// Frame info
/// ```
/// When free
/// 31                 20           0
/// [nnnnnnnnnnnnnnnnnnnn           1]
///  ^-- next free index            ^-- free bit
///
/// When allocated
/// 31                           30 0
/// [ssssssssssssssssssssssssssssss 0]
///  ^-- ptr to shared frame info  ^^-- free bit
///                                |
///                                +-- PD bit
/// ```
#[repr(C, packed)]
pub struct FrameInfo(usize);

/// A struct to keep track of information related to shared
/// physical frames.
#[allow(dead_code)]
pub struct SharedFrameInfo {
    /// needs to be at least 4B aligned
    pad: u32,

    /// list of sharers: (pid, vaddr)
    list: StaticLinkedList<(usize, usize)>,
}

impl Frame {
    /// Allocate a frame and return its physical address
    pub fn alloc() -> usize {
        let all_frames = unsafe { &mut *FRAME_INFO };

        no_interrupts(|| {
            // get a frame
            let free = unsafe { FREE_FRAMES };

            if free == 0 {
                // TODO: page out
                panic!("Out of physical memory");
            }

            all_frames[free].alloc();

            free << 12
        })
    }

    /// Free the frame with the given index
    pub fn free(index: usize) {
        let all_frames = unsafe { &mut *FRAME_INFO };
        no_interrupts(|| all_frames[index].free());
    }

    /// Add the given pid as a sharer of this frame.
    pub fn share(pid: usize, vaddr: usize, paddr: usize) {
        // TODO: deal with a frame being shared multiple times
        // by the same process

        let all_frames = unsafe { &mut *FRAME_INFO };
        let index = paddr >> 12;

        no_interrupts(|| {
            let frame = &mut all_frames[index];
            let sfi = if frame.has_shared_info() {
                frame.get_shared_info().expect("No shared frame info!")
            } else {
                let raw_sfi = Box::into_raw(box SharedFrameInfo::new());
                frame.set_shared_info(raw_sfi);
                unsafe { &mut *raw_sfi }
            };

            sfi.list.push_back((pid, vaddr));
        });

        // printf!("Shared {:X} {:X}\n", vaddr, paddr);
    }
}

/// Make the words of a frame indexable
impl Index<usize> for Frame {
    type Output = usize;

    fn index<'a>(&'a self, index: usize) -> &'a usize {
        unsafe { &self.0[index] }
    }
}

/// Make the words of a frame indexable
impl IndexMut<usize> for Frame {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut usize {
        unsafe { &mut self.0[index] }
    }
}

/// Make the `FrameInfoSection` indexable
impl Index<usize> for FrameInfoSection {
    type Output = FrameInfo;

    fn index<'a>(&'a self, index: usize) -> &'a FrameInfo {
        &self.0[index]
    }
}

/// Make the `FrameInfoSection` indexable
impl IndexMut<usize> for FrameInfoSection {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut FrameInfo {
        &mut self.0[index]
    }
}

impl FrameInfo {
    /// Allocate the frame referred to by this `FrameInfo`.
    /// NOTE: this should only be called on the first frame in the free list
    pub fn alloc(&mut self) {
        if self.get_index() != unsafe { FREE_FRAMES } {
            panic!("Attempt to alloc middle free frame {}", self.get_index());
        }

        // Remove from list
        no_interrupts(|| unsafe { FREE_FRAMES = self.get_next_free() });

        // mark not free
        self.clear_shared_info();
        self.set_free(false);
    }

    /// Free the frame referred to by this FrameInfo if this is the last sharere; otherwise, just
    /// remove this process's `SharedFrameInfo`.
    pub fn free(&mut self) {
        // remove shared page info for this process
        let pid = unsafe { (*CURRENT_PROCESS).get_pid() };
        let mut dealloced = false;
        if self.has_shared_info() {
            let sfi_list = &mut self.get_shared_info()
                .expect("No shared frame info to free")
                .list;
            let i = sfi_list
                .iter()
                .position(|&(req_pid, _)| req_pid == pid)
                .expect("Attempt to free shared page which this process is not sharing!");
            let _ = sfi_list.remove(i);

            // if no more sharers, drop the shared info
            if sfi_list.is_empty() {
                let addr = self.0 & !3;
                let ptr = addr as *mut SharedFrameInfo;
                off();
                unsafe {
                    Box::from_raw(ptr);
                }
                dealloced = true;
            }
        }

        if dealloced {
            self.clear_shared_info();
            on();
        }

        // if there is only one "sharer" left, free the page
        if !self.has_shared_info() {
            // mark free
            self.set_free(true);

            // add to free list
            off();

            unsafe {
                self.set_next_free(FREE_FRAMES);
                FREE_FRAMES = self.get_index();
            }

            on();
        }
    }

    /// Get the index of the `Frame`
    pub fn get_index(&self) -> usize {
        let first = unsafe { FRAME_INFO as *const FrameInfoSection as usize };
        let addr = self as *const FrameInfo as usize;
        (addr - first) / 4
    }

    /// Set the free bit of this `FrameInfo` to 1 if `free` is true; else 0
    fn set_free(&mut self, free: bool) {
        let base = self.0 & !1;
        self.0 = base | if free { 1 } else { 0 }
    }

    /// Get the index of the next free frame
    fn get_next_free(&self) -> usize {
        self.0 >> 12
    }

    /// Set the index of the next free frame
    fn set_next_free(&mut self, next: usize) {
        let base = self.0 & 0xFFF;
        self.0 = (next << 12) | base;
    }

    /// Returns true if this frame has shared frame info.
    ///
    /// NOTE: this does not mean the frame is shared yet.
    fn has_shared_info(&self) -> bool {
        self.get_shared_info().is_some()
    }

    /// Get the `SharedFrameInfo` of this frame
    fn get_shared_info(&self) -> Option<&mut SharedFrameInfo> {
        let addr = self.0 & !3;
        let ptr = addr as *mut SharedFrameInfo;

        if ptr.is_null() {
            None
        } else {
            unsafe { Some(&mut *ptr) }
        }
    }

    /// Set the `SharedFrameInfo` of this frame
    fn set_shared_info(&mut self, sfi: *mut SharedFrameInfo) {
        if self.get_shared_info().is_some() {
            panic!("Attempt to overwrite shared frame info!");
        }

        let addr = (sfi as usize) & !3;
        let base = self.0 & 3;

        self.0 = addr | base;
    }

    /// Remove the `SharedFrameInfo` ptr of the frame
    fn clear_shared_info(&mut self) {
        self.0 &= 3;
    }
}

impl SharedFrameInfo {
    fn new() -> SharedFrameInfo {
        SharedFrameInfo {
            pad: 0,
            list: StaticLinkedList::new(),
        }
    }
}

/// Initialize physical memory frames using the rest of physical memory.
/// This function detects all available physical memory.
pub fn init(start: usize) {
    if start % 0x400000 != 0 {
        panic!("phys mem start must be 4MiB aligned!");
    }

    unsafe {
        // round start up to nearest page boundary
        FRAME_INFO = if start % 0x1000 == 0 {
            start
        } else {
            start - (start % 0x1000) + 0x1000
        } as *mut FrameInfoSection;
    }

    let all_frames = unsafe { &mut *FRAME_INFO };

    // Detect available memory
    let mem = RegionMap::new((8 << 20) as *mut Frame);
    let mut num_frames = 0;

    // add all available frames to free list
    for (base, num) in mem {
        for i in base..(base + num) {
            all_frames[i].free();
        }
        num_frames += num;
    }

    bootlog!(
        "phys mem inited - metadata @ 0x{:X}, {} frames\n",
        start,
        num_frames
    );
}
<commit_msg>remove another off/on<commit_after>//! Physical memory management

use alloc::boxed::Box;

use core::ops::{Index, IndexMut};

use interrupts::no_interrupts;
use process::CURRENT_PROCESS;
use static_linked_list::StaticLinkedList;

use super::regionmap::RegionMap;

/// Array of `FrameInfo`. This is a pointer to the region of memory used
/// to hold physical memory allocation metadata.
static mut FRAME_INFO: *mut FrameInfoSection = 0 as *mut FrameInfoSection;

/// The index of the first free frame in a LIFO list.
/// 0 => empty list
static mut FREE_FRAMES: usize = 0;

/// A physical memory frame
#[repr(C, packed)]
pub struct Frame([usize; 1024]);

/// Should take up 4MiB on a 32-bit machine.
/// There is one frame info for each frame, associated by frame index
#[repr(C, packed)]
pub struct FrameInfoSection([FrameInfo; 1 << 20]);

/// Frame info
/// ```
/// When free
/// 31                 20           0
/// [nnnnnnnnnnnnnnnnnnnn           1]
///  ^-- next free index            ^-- free bit
///
/// When allocated
/// 31                           30 0
/// [ssssssssssssssssssssssssssssss 0]
///  ^-- ptr to shared frame info  ^^-- free bit
///                                |
///                                +-- PD bit
/// ```
#[repr(C, packed)]
pub struct FrameInfo(usize);

/// A struct to keep track of information related to shared
/// physical frames.
#[allow(dead_code)]
pub struct SharedFrameInfo {
    /// needs to be at least 4B aligned
    pad: u32,

    /// list of sharers: (pid, vaddr)
    list: StaticLinkedList<(usize, usize)>,
}

impl Frame {
    /// Allocate a frame and return its physical address
    pub fn alloc() -> usize {
        let all_frames = unsafe { &mut *FRAME_INFO };

        no_interrupts(|| {
            // get a frame
            let free = unsafe { FREE_FRAMES };

            if free == 0 {
                // TODO: page out
                panic!("Out of physical memory");
            }

            all_frames[free].alloc();

            free << 12
        })
    }

    /// Free the frame with the given index
    pub fn free(index: usize) {
        let all_frames = unsafe { &mut *FRAME_INFO };
        no_interrupts(|| all_frames[index].free());
    }

    /// Add the given pid as a sharer of this frame.
    pub fn share(pid: usize, vaddr: usize, paddr: usize) {
        // TODO: deal with a frame being shared multiple times
        // by the same process

        let all_frames = unsafe { &mut *FRAME_INFO };
        let index = paddr >> 12;

        no_interrupts(|| {
            let frame = &mut all_frames[index];
            let sfi = if frame.has_shared_info() {
                frame.get_shared_info().expect("No shared frame info!")
            } else {
                let raw_sfi = Box::into_raw(box SharedFrameInfo::new());
                frame.set_shared_info(raw_sfi);
                unsafe { &mut *raw_sfi }
            };

            sfi.list.push_back((pid, vaddr));
        });

        // printf!("Shared {:X} {:X}\n", vaddr, paddr);
    }
}

/// Make the words of a frame indexable
impl Index<usize> for Frame {
    type Output = usize;

    fn index<'a>(&'a self, index: usize) -> &'a usize {
        unsafe { &self.0[index] }
    }
}

/// Make the words of a frame indexable
impl IndexMut<usize> for Frame {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut usize {
        unsafe { &mut self.0[index] }
    }
}

/// Make the `FrameInfoSection` indexable
impl Index<usize> for FrameInfoSection {
    type Output = FrameInfo;

    fn index<'a>(&'a self, index: usize) -> &'a FrameInfo {
        &self.0[index]
    }
}

/// Make the `FrameInfoSection` indexable
impl IndexMut<usize> for FrameInfoSection {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut FrameInfo {
        &mut self.0[index]
    }
}

impl FrameInfo {
    /// Allocate the frame referred to by this `FrameInfo`.
    /// NOTE: this should only be called on the first frame in the free list
    pub fn alloc(&mut self) {
        if self.get_index() != unsafe { FREE_FRAMES } {
            panic!("Attempt to alloc middle free frame {}", self.get_index());
        }

        // Remove from list
        no_interrupts(|| unsafe { FREE_FRAMES = self.get_next_free() });

        // mark not free
        self.clear_shared_info();
        self.set_free(false);
    }

    /// Free the frame referred to by this FrameInfo if this is the last sharere; otherwise, just
    /// remove this process's `SharedFrameInfo`.
    pub fn free(&mut self) {
        // remove shared page info for this process
        let pid = unsafe { (*CURRENT_PROCESS).get_pid() };
        if self.has_shared_info() {
            // remove this share
            {
                let sfi_list = &mut self.get_shared_info()
                    .expect("No shared frame info to free")
                    .list;
                let i = sfi_list
                    .iter()
                    .position(|&(req_pid, _)| req_pid == pid)
                    .expect("Attempt to free shared page which this process is not sharing!");
                let _ = sfi_list.remove(i);
            }

            // if no more sharers, drop the shared info
            if self.get_shared_info().unwrap().list.is_empty() {
                let addr = self.0 & !3;
                let ptr = addr as *mut SharedFrameInfo;
                no_interrupts(|| {
                    unsafe { drop(Box::from_raw(ptr)) };
                    self.clear_shared_info();
                })
            }
        }

        // if there is only one "sharer" left, free the page
        if !self.has_shared_info() {
            // mark free
            self.set_free(true);

            // add to free list
            no_interrupts(|| unsafe {
                self.set_next_free(FREE_FRAMES);
                FREE_FRAMES = self.get_index();
            });
        }
    }

    /// Get the index of the `Frame`
    pub fn get_index(&self) -> usize {
        let first = unsafe { FRAME_INFO as *const FrameInfoSection as usize };
        let addr = self as *const FrameInfo as usize;
        (addr - first) / 4
    }

    /// Set the free bit of this `FrameInfo` to 1 if `free` is true; else 0
    fn set_free(&mut self, free: bool) {
        let base = self.0 & !1;
        self.0 = base | if free { 1 } else { 0 }
    }

    /// Get the index of the next free frame
    fn get_next_free(&self) -> usize {
        self.0 >> 12
    }

    /// Set the index of the next free frame
    fn set_next_free(&mut self, next: usize) {
        let base = self.0 & 0xFFF;
        self.0 = (next << 12) | base;
    }

    /// Returns true if this frame has shared frame info.
    ///
    /// NOTE: this does not mean the frame is shared yet.
    fn has_shared_info(&self) -> bool {
        self.get_shared_info().is_some()
    }

    /// Get the `SharedFrameInfo` of this frame
    fn get_shared_info(&self) -> Option<&mut SharedFrameInfo> {
        let addr = self.0 & !3;
        let ptr = addr as *mut SharedFrameInfo;

        if ptr.is_null() {
            None
        } else {
            unsafe { Some(&mut *ptr) }
        }
    }

    /// Set the `SharedFrameInfo` of this frame
    fn set_shared_info(&mut self, sfi: *mut SharedFrameInfo) {
        if self.get_shared_info().is_some() {
            panic!("Attempt to overwrite shared frame info!");
        }

        let addr = (sfi as usize) & !3;
        let base = self.0 & 3;

        self.0 = addr | base;
    }

    /// Remove the `SharedFrameInfo` ptr of the frame
    fn clear_shared_info(&mut self) {
        self.0 &= 3;
    }
}

impl SharedFrameInfo {
    fn new() -> SharedFrameInfo {
        SharedFrameInfo {
            pad: 0,
            list: StaticLinkedList::new(),
        }
    }
}

/// Initialize physical memory frames using the rest of physical memory.
/// This function detects all available physical memory.
pub fn init(start: usize) {
    if start % 0x400000 != 0 {
        panic!("phys mem start must be 4MiB aligned!");
    }

    unsafe {
        // round start up to nearest page boundary
        FRAME_INFO = if start % 0x1000 == 0 {
            start
        } else {
            start - (start % 0x1000) + 0x1000
        } as *mut FrameInfoSection;
    }

    let all_frames = unsafe { &mut *FRAME_INFO };

    // Detect available memory
    let mem = RegionMap::new((8 << 20) as *mut Frame);
    let mut num_frames = 0;

    // add all available frames to free list
    for (base, num) in mem {
        for i in base..(base + num) {
            all_frames[i].free();
        }
        num_frames += num;
    }

    bootlog!(
        "phys mem inited - metadata @ 0x{:X}, {} frames\n",
        start,
        num_frames
    );
}
<|endoftext|>