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

//! The compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{self, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
use syntax::ext::base::MultiModifier;
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap;
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;
use syntax_pos::Span;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

macro_rules! path_std {
    ($($x:tt)*) => (
        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
    )
}

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod debug;
pub mod default;
pub mod custom;

#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;

pub mod generic;

fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
    Span {
        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
            call_site: span,
            callee: codemap::NameAndSpan {
                format: codemap::MacroAttribute(intern(attr_name)),
                span: Some(span),
                allow_internal_unstable: true,
            },
        }),
        ..span
    }
}

fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Vec<Annotatable> {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let mut item = match annotatable {
        Annotatable::Item(item) => item,
        other => {
            cx.span_err(span, "`derive` can only be applied to items");
            return vec![other]
        }
    };

    if mitem.value_str().is_some() {
        cx.span_err(mitem.span, "unexpected value in `derive`");
    }

    let traits = mitem.meta_item_list().unwrap_or(&[]);
    if traits.is_empty() {
        cx.span_warn(mitem.span, "empty trait list in `derive`");
    }

    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
    // `#[structural_match]` attribute.
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") {
        let structural_match = intern_and_get_ident("structural_match");
        let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
        let meta = cx.meta_word(span, structural_match);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
    // the same as the copy implementation.
    //
    // Add a marker attribute here picked up during #[derive(Clone)]
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") {
        let marker = intern_and_get_ident("rustc_copy_clone_marker");
        let span = allow_unstable(cx, span, "derive(Copy, Clone)");
        let meta = cx.meta_word(span, marker);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    let mut other_items = Vec::new();

    let mut iter = traits.iter();
    while let Some(titem) = iter.next() {

        let tword = match titem.word() {
            Some(name) => name,
            None => {
                cx.span_err(titem.span, "malformed `derive` entry");
                continue
            }
        };
        let tname = tword.name();

        // If this is a built-in derive mode, then we expand it immediately
        // here.
        if is_builtin_trait(&tname) {
            let name = intern_and_get_ident(&format!("derive({})", tname));
            let mitem = cx.meta_word(titem.span, name);

            let span = Span {
                expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                    call_site: titem.span,
                    callee: codemap::NameAndSpan {
                        format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
                        span: Some(titem.span),
                        allow_internal_unstable: true,
                    },
                }),
                ..titem.span
            };

            let my_item = Annotatable::Item(item);
            expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
                other_items.push(a);
            });
            item = my_item.expect_item();

        // Otherwise if this is a `rustc_macro`-style derive mode, we process it
        // here. The logic here is to:
        //
        // 1. Collect the remaining `#[derive]` annotations into a list. If
        //    there are any left, attach a `#[derive]` attribute to the item
        //    that we're currently expanding with the remaining derive modes.
        // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
        // 3. Expand the current item we're expanding, getting back a list of
        //    items that replace it.
        // 4. Extend the returned list with the current list of items we've
        //    collected so far.
        // 5. Return everything!
        //
        // If custom derive extensions end up threading through the `#[derive]`
        // attribute, we'll get called again later on to continue expanding
        // those modes.
        } else if let Some(ext) = cx.derive_modes.remove(&tname) {
            let remaining_derives = iter.cloned().collect::<Vec<_>>();
            if remaining_derives.len() > 0 {
                let list = cx.meta_list(titem.span,
                                        intern_and_get_ident("derive"),
                                        remaining_derives);
                let attr = cx.attribute(titem.span, list);
                item = item.map(|mut i| {
                    i.attrs.push(attr);
                    i
                });
            }
            let titem = cx.meta_list_item_word(titem.span, tname.clone());
            let mitem = cx.meta_list(titem.span,
                                     intern_and_get_ident("derive"),
                                     vec![titem]);
            let item = Annotatable::Item(item);
            let mut items = ext.expand(cx, mitem.span, &mitem, item);
            items.extend(other_items);
            cx.derive_modes.insert(tname.clone(), ext);
            return items

        // If we've gotten this far then it means that we're in the territory of
        // the old custom derive mechanism. If the feature isn't enabled, we
        // issue an error, otherwise manufacture the `derive_Foo` attribute.
        } else if !cx.ecfg.enable_custom_derive() {
            feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
                                           "custom_derive",
                                           titem.span,
                                           feature_gate::GateIssue::Language,
                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
        } else {
            let name = intern_and_get_ident(&format!("derive_{}", tname));
            let mitem = cx.meta_word(titem.span, name);
            item = item.map(|mut i| {
                i.attrs.push(cx.attribute(mitem.span, mitem));
                i
            });
        }
    }

    other_items.insert(0, Annotatable::Item(item));
    return other_items
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn register_all(env: &mut SyntaxEnv) {
            env.insert(intern("derive"), MultiModifier(Box::new(expand_derive)));
        }

        pub fn is_builtin_trait(name: &str) -> bool {
            match name {
                $( $name )|+ => true,
                _ => false,
            }
        }

        fn expand_builtin(name: &str,
                          ecx: &mut ExtCtxt,
                          span: Span,
                          mitem: &MetaItem,
                          item: &Annotatable,
                          push: &mut FnMut(Annotatable)) {
            match name {
                $(
                    $name => {
                        warn_if_deprecated(ecx, span, $name);
                        $func(ecx, span, mitem, item, push);
                    }
                )*
                _ => panic!("not a builtin derive mode: {}", name),
            }
        }
    }
}

derive_traits! {
    "Clone" => clone::expand_deriving_clone,

    "Hash" => hash::expand_deriving_hash,

    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,

    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,

    "PartialEq" => partial_eq::expand_deriving_partial_eq,
    "Eq" => eq::expand_deriving_eq,
    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
    "Ord" => ord::expand_deriving_ord,

    "Debug" => debug::expand_deriving_debug,

    "Default" => default::expand_deriving_default,

    "Send" => bounds::expand_deriving_unsafe_bound,
    "Sync" => bounds::expand_deriving_unsafe_bound,
    "Copy" => bounds::expand_deriving_copy,

    // deprecated
    "Encodable" => encodable::expand_deriving_encodable,
    "Decodable" => decodable::expand_deriving_decodable,
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
    if let Some(replacement) = match name {
        "Encodable" => Some("RustcEncodable"),
        "Decodable" => Some("RustcDecodable"),
        _ => None,
    } {
        ecx.span_warn(sp,
                      &format!("derive({}) is deprecated in favor of derive({})",
                               name,
                               replacement));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
            ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>)
                  -> P<ast::Expr> {
    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![cx.stmt_expr(call)],
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span,
    }))
}
<commit_msg>Avoid instaiblity errors in code generated by `syntax_ext::deriving::call_intrinsic()`.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[derive]` extensions.

use syntax::ast::{self, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
use syntax::ext::base::MultiModifier;
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap;
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;
use syntax_pos::Span;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

macro_rules! path_std {
    ($($x:tt)*) => (
        ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) )
    )
}

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod debug;
pub mod default;
pub mod custom;

#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/partial_ord.rs"]
pub mod partial_ord;
#[path="cmp/ord.rs"]
pub mod ord;

pub mod generic;

fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
    Span {
        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
            call_site: span,
            callee: codemap::NameAndSpan {
                format: codemap::MacroAttribute(intern(attr_name)),
                span: Some(span),
                allow_internal_unstable: true,
            },
        }),
        ..span
    }
}

fn expand_derive(cx: &mut ExtCtxt,
                 span: Span,
                 mitem: &MetaItem,
                 annotatable: Annotatable)
                 -> Vec<Annotatable> {
    debug!("expand_derive: span = {:?}", span);
    debug!("expand_derive: mitem = {:?}", mitem);
    debug!("expand_derive: annotatable input  = {:?}", annotatable);
    let mut item = match annotatable {
        Annotatable::Item(item) => item,
        other => {
            cx.span_err(span, "`derive` can only be applied to items");
            return vec![other]
        }
    };

    if mitem.value_str().is_some() {
        cx.span_err(mitem.span, "unexpected value in `derive`");
    }

    let traits = mitem.meta_item_list().unwrap_or(&[]);
    if traits.is_empty() {
        cx.span_warn(mitem.span, "empty trait list in `derive`");
    }

    // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
    // `#[structural_match]` attribute.
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") {
        let structural_match = intern_and_get_ident("structural_match");
        let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
        let meta = cx.meta_word(span, structural_match);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
    // the same as the copy implementation.
    //
    // Add a marker attribute here picked up during #[derive(Clone)]
    if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") &&
       traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") {
        let marker = intern_and_get_ident("rustc_copy_clone_marker");
        let span = allow_unstable(cx, span, "derive(Copy, Clone)");
        let meta = cx.meta_word(span, marker);
        item = item.map(|mut i| {
            i.attrs.push(cx.attribute(span, meta));
            i
        });
    }

    let mut other_items = Vec::new();

    let mut iter = traits.iter();
    while let Some(titem) = iter.next() {

        let tword = match titem.word() {
            Some(name) => name,
            None => {
                cx.span_err(titem.span, "malformed `derive` entry");
                continue
            }
        };
        let tname = tword.name();

        // If this is a built-in derive mode, then we expand it immediately
        // here.
        if is_builtin_trait(&tname) {
            let name = intern_and_get_ident(&format!("derive({})", tname));
            let mitem = cx.meta_word(titem.span, name);

            let span = Span {
                expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
                    call_site: titem.span,
                    callee: codemap::NameAndSpan {
                        format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
                        span: Some(titem.span),
                        allow_internal_unstable: true,
                    },
                }),
                ..titem.span
            };

            let my_item = Annotatable::Item(item);
            expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| {
                other_items.push(a);
            });
            item = my_item.expect_item();

        // Otherwise if this is a `rustc_macro`-style derive mode, we process it
        // here. The logic here is to:
        //
        // 1. Collect the remaining `#[derive]` annotations into a list. If
        //    there are any left, attach a `#[derive]` attribute to the item
        //    that we're currently expanding with the remaining derive modes.
        // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
        // 3. Expand the current item we're expanding, getting back a list of
        //    items that replace it.
        // 4. Extend the returned list with the current list of items we've
        //    collected so far.
        // 5. Return everything!
        //
        // If custom derive extensions end up threading through the `#[derive]`
        // attribute, we'll get called again later on to continue expanding
        // those modes.
        } else if let Some(ext) = cx.derive_modes.remove(&tname) {
            let remaining_derives = iter.cloned().collect::<Vec<_>>();
            if remaining_derives.len() > 0 {
                let list = cx.meta_list(titem.span,
                                        intern_and_get_ident("derive"),
                                        remaining_derives);
                let attr = cx.attribute(titem.span, list);
                item = item.map(|mut i| {
                    i.attrs.push(attr);
                    i
                });
            }
            let titem = cx.meta_list_item_word(titem.span, tname.clone());
            let mitem = cx.meta_list(titem.span,
                                     intern_and_get_ident("derive"),
                                     vec![titem]);
            let item = Annotatable::Item(item);
            let mut items = ext.expand(cx, mitem.span, &mitem, item);
            items.extend(other_items);
            cx.derive_modes.insert(tname.clone(), ext);
            return items

        // If we've gotten this far then it means that we're in the territory of
        // the old custom derive mechanism. If the feature isn't enabled, we
        // issue an error, otherwise manufacture the `derive_Foo` attribute.
        } else if !cx.ecfg.enable_custom_derive() {
            feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
                                           "custom_derive",
                                           titem.span,
                                           feature_gate::GateIssue::Language,
                                           feature_gate::EXPLAIN_CUSTOM_DERIVE);
        } else {
            let name = intern_and_get_ident(&format!("derive_{}", tname));
            let mitem = cx.meta_word(titem.span, name);
            item = item.map(|mut i| {
                i.attrs.push(cx.attribute(mitem.span, mitem));
                i
            });
        }
    }

    other_items.insert(0, Annotatable::Item(item));
    return other_items
}

macro_rules! derive_traits {
    ($( $name:expr => $func:path, )+) => {
        pub fn register_all(env: &mut SyntaxEnv) {
            env.insert(intern("derive"), MultiModifier(Box::new(expand_derive)));
        }

        pub fn is_builtin_trait(name: &str) -> bool {
            match name {
                $( $name )|+ => true,
                _ => false,
            }
        }

        fn expand_builtin(name: &str,
                          ecx: &mut ExtCtxt,
                          span: Span,
                          mitem: &MetaItem,
                          item: &Annotatable,
                          push: &mut FnMut(Annotatable)) {
            match name {
                $(
                    $name => {
                        warn_if_deprecated(ecx, span, $name);
                        $func(ecx, span, mitem, item, push);
                    }
                )*
                _ => panic!("not a builtin derive mode: {}", name),
            }
        }
    }
}

derive_traits! {
    "Clone" => clone::expand_deriving_clone,

    "Hash" => hash::expand_deriving_hash,

    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,

    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,

    "PartialEq" => partial_eq::expand_deriving_partial_eq,
    "Eq" => eq::expand_deriving_eq,
    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
    "Ord" => ord::expand_deriving_ord,

    "Debug" => debug::expand_deriving_debug,

    "Default" => default::expand_deriving_default,

    "Send" => bounds::expand_deriving_unsafe_bound,
    "Sync" => bounds::expand_deriving_unsafe_bound,
    "Copy" => bounds::expand_deriving_copy,

    // deprecated
    "Encodable" => encodable::expand_deriving_encodable,
    "Decodable" => decodable::expand_deriving_decodable,
}

#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
    if let Some(replacement) = match name {
        "Encodable" => Some("RustcEncodable"),
        "Decodable" => Some("RustcDecodable"),
        _ => None,
    } {
        ecx.span_warn(sp,
                      &format!("derive({}) is deprecated in favor of derive({})",
                               name,
                               replacement));
    }
}

/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
    let mut typaram = String::from(base);
    if let Annotatable::Item(ref item) = *item {
        match item.node {
            ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) |
            ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => {
                for ty in ty_params.iter() {
                    typaram.push_str(&ty.ident.name.as_str());
                }
            }

            _ => {}
        }
    }

    typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
                  mut span: Span,
                  intrinsic: &str,
                  args: Vec<P<ast::Expr>>)
                  -> P<ast::Expr> {
    span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
        call_site: span,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute(intern("derive")),
            span: Some(span),
            allow_internal_unstable: true,
        },
    });

    let path = cx.std_path(&["intrinsics", intrinsic]);
    let call = cx.expr_call_global(span, path, args);

    cx.expr_block(P(ast::Block {
        stmts: vec![cx.stmt_expr(call)],
        id: ast::DUMMY_NODE_ID,
        rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
        span: span,
    }))
}
<|endoftext|>


<commit_before>//! Removes assignments to ZST places.

use crate::transform::MirPass;
use rustc_middle::mir::{Body, StatementKind};
use rustc_middle::ty::TyCtxt;

pub struct RemoveZsts;

impl<'tcx> MirPass<'tcx> for RemoveZsts {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        let param_env = tcx.param_env(body.source.def_id());
        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
        for block in basic_blocks.iter_mut() {
            for statement in block.statements.iter_mut() {
                match statement.kind {
                    StatementKind::Assign(box (place, _)) => {
                        let place_ty = place.ty(local_decls, tcx).ty;
                        if let Ok(layout) = tcx.layout_of(param_env.and(place_ty)) {
                            if layout.is_zst() {
                                if tcx.consider_optimizing(|| {
                                    format!(
                                        "RemoveZsts - Place: {:?} SourceInfo: {:?}",
                                        place, statement.source_info
                                    )
                                }) {
                                    statement.make_nop();
                                }
                            }
                        }
                    }
                    _ => {}
                }
            }
        }
    }
}
<commit_msg>avoid calling  for types which can't be ZSTs<commit_after>//! Removes assignments to ZST places.

use crate::transform::MirPass;
use rustc_middle::mir::{Body, StatementKind};
use rustc_middle::ty::{self, Ty, TyCtxt};

pub struct RemoveZsts;

impl<'tcx> MirPass<'tcx> for RemoveZsts {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        let param_env = tcx.param_env(body.source.def_id());
        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
        for block in basic_blocks.iter_mut() {
            for statement in block.statements.iter_mut() {
                match statement.kind {
                    StatementKind::Assign(box (place, _)) => {
                        let place_ty = place.ty(local_decls, tcx).ty;
                        if !maybe_zst(place_ty) {
                            continue;
                        }
                        let layout = match tcx.layout_of(param_env.and(place_ty)) {
                            Ok(layout) => layout,
                            Err(_) => continue,
                        };
                        if !layout.is_zst() {
                            continue;
                        }
                        if tcx.consider_optimizing(|| {
                            format!(
                                "RemoveZsts - Place: {:?} SourceInfo: {:?}",
                                place, statement.source_info
                            )
                        }) {
                            statement.make_nop();
                        }
                    }
                    _ => {}
                }
            }
        }
    }
}

/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
fn maybe_zst(ty: Ty<'_>) -> bool {
    match ty.kind() {
        // maybe ZST (could be more precise)
        ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
        // definitely ZST
        ty::FnDef(..) | ty::Never => true,
        // unreachable or can't be ZST
        _ => false,
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the filesystems action.
//!
//! The filesystems action lists all mounted filesystems on the client,
//! collecting device name, mount point, filesystem type and its options.
//! Current implementation works only in Linux systems.

use crate::session::{self, Session};

use log::error;
use std::fmt::{Display, Formatter};

/// Enum of possible errors, which can occur during collecting filesystems data.
#[derive(Debug)]
enum Error {
    /// Missing mtab-like file error.
    MissingFile(std::io::Error),
    /// Parsing mtab-like file error.
    MountInfoParse(std::io::Error),
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            MissingFile(ref error) => Some(error),
            MountInfoParse(ref error) => Some(error),
        }
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            MissingFile(ref error) => {
                write!(fmt, "missed file error: {}", error)
            },
            MountInfoParse(ref error) => {
                write!(fmt, "failed to obtain mount information: {}", error)
            },
        }
    }
}

impl From<Error> for session::Error {

    fn from(error: Error) -> session::Error {
        session::Error::action(error)
    }
}

/// A response type for the filesystems action.
pub struct Response {
    /// Information about the filesystem.
    mount_info: proc_mounts::MountInfo,
}

/// Handles requests for the filesystems action.
///
/// Initially searches in `/proc/mounts`. If it's missing, falls back to
/// `/etc/mtab`.
pub fn handle<S: Session>(session: &mut S, _: ()) -> session::Result<()> {
    use proc_mounts::MountIter;

    // Check whether `/proc/mounts` exists.
    let mount_iter = match MountIter::new() {
        Ok(mount_iter) => mount_iter,
        Err(_) => {
            // `/proc/mounts` doesn't exist. Try to fall back to `/etc/mtab`.
            MountIter::new_from_file("/etc/mtab").map_err(Error::MissingFile)?
        },
    };

    for mount_info in mount_iter {
        let mount_info = mount_info.map_err(Error::MountInfoParse)?;
        session.reply(Response {
           mount_info,
        })?;
    }

    Ok(())
}

/// Converts filesystem mount option in `String` representation to
/// GRR's `KeyValue` protobuf struct representation.
fn option_to_key_value(option: String) -> rrg_proto::jobs::KeyValue {
    match &option.split('=').collect::<Vec<&str>>()[..] {
        &[key] => rrg_proto::jobs::KeyValue::key(String::from(key)),
        &[key, value] => rrg_proto::jobs::KeyValue::pair(String::from(key), String::from(value)),
        _ => {
            error!("invalid mount option syntax: {}", option);
            // TODO: It's better not to send any key-value in this case.
            rrg_proto::jobs::KeyValue::new()
        },
    }
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("Filesystem");

    type Proto = rrg_proto::sysinfo::Filesystem;

    fn into_proto(self) -> rrg_proto::sysinfo::Filesystem {
        let options: rrg_proto::jobs::AttributedDict = self.mount_info.options.into_iter()
            .map(option_to_key_value)
            .collect();

        // TODO: Remove lossy conversion of `PathBuf` to `String`
        // when `mount_point` and `device` fields of `Filesystem` message
        // will have `bytes` type instead of `string`.
        let mut proto = rrg_proto::sysinfo::Filesystem::new();
        proto.set_device(self.mount_info.source.to_string_lossy().into_owned());
        proto.set_mount_point(self.mount_info.dest.to_string_lossy().into_owned());
        proto.set_field_type(self.mount_info.fstype);
        proto.set_options(options);

        proto
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use std::path::PathBuf;

    #[test]
    fn test_if_any_filesystem_exists() {
        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());
        assert_ne!(session.reply_count(), 0);
    }

    #[cfg(feature = "test-fuse")]
    #[test]
    fn test_fuse_filesystem() {
        /// Unit-like struct, representing a filesystem for testing with `fuse`.
        struct FuseFilesystem;

        impl fuse::Filesystem for FuseFilesystem {}

        let fs_name = PathBuf::from("fuse-test-fs");

        let tmp_dir = tempfile::tempdir().unwrap();
        let mountpoint = tmp_dir.path();

        let fs_name_option = format!("fsname={}", fs_name.to_str().unwrap());
        let options = [
            "-o", "ro",
            "-o", "nosuid",
            "-o", "nodev",
            "-o", "relatime",
            "-o", "subtype=custom-type",
            "-o", &fs_name_option,
        ];
        let options = options.iter().map(|opt| opt.as_ref())
            .collect::<Vec<&std::ffi::OsStr>>();

        // Spawn a background thread to handle filesystem operations.
        // When `_background_session` is dropped, filesystem will be unmounted.
        let background_session = unsafe {
            fuse::spawn_mount(FuseFilesystem, &mountpoint, &options).unwrap()
        };

        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());

        let fuse_mounted_fs = session.replies::<Response>()
            .find(|reply| reply.mount_info.source == fs_name)
            .expect("no reply with a mounted FUSE filesystem");

        let mount_info = &fuse_mounted_fs.mount_info;
        assert_eq!(mount_info.source, fs_name);
        assert_eq!(mount_info.dest, tmp_dir.path());
        assert_eq!(mount_info.fstype, "fuse.custom-type");

        let options = &mount_info.options;
        assert!(options.iter().any(|opt| opt == "ro"));
        assert!(options.iter().any(|opt| opt == "nosuid"));
        assert!(options.iter().any(|opt| opt == "nodev"));
        assert!(options.iter().any(|opt| opt == "relatime"));

        let uid = unsafe { libc::getuid() };
        let gid = unsafe { libc::getgid() };

        // `user_id` and `group_id` are set by libfuse.
        // http://man7.org/linux/man-pages/man8/mount.fuse.8.html
        let current_uid_option = format!("user_id={}", uid);
        assert!(options.iter().any(|opt| *opt == current_uid_option));

        let current_gid_option = format!("group_id={}", gid);
        assert!(options.iter().any(|opt| *opt == current_gid_option));

        drop(background_session);
    }
}
<commit_msg>Fix a compiler warning.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the filesystems action.
//!
//! The filesystems action lists all mounted filesystems on the client,
//! collecting device name, mount point, filesystem type and its options.
//! Current implementation works only in Linux systems.

use crate::session::{self, Session};

use log::error;
use std::fmt::{Display, Formatter};

/// Enum of possible errors, which can occur during collecting filesystems data.
#[derive(Debug)]
enum Error {
    /// Missing mtab-like file error.
    MissingFile(std::io::Error),
    /// Parsing mtab-like file error.
    MountInfoParse(std::io::Error),
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            MissingFile(ref error) => Some(error),
            MountInfoParse(ref error) => Some(error),
        }
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            MissingFile(ref error) => {
                write!(fmt, "missed file error: {}", error)
            },
            MountInfoParse(ref error) => {
                write!(fmt, "failed to obtain mount information: {}", error)
            },
        }
    }
}

impl From<Error> for session::Error {

    fn from(error: Error) -> session::Error {
        session::Error::action(error)
    }
}

/// A response type for the filesystems action.
pub struct Response {
    /// Information about the filesystem.
    mount_info: proc_mounts::MountInfo,
}

/// Handles requests for the filesystems action.
///
/// Initially searches in `/proc/mounts`. If it's missing, falls back to
/// `/etc/mtab`.
pub fn handle<S: Session>(session: &mut S, _: ()) -> session::Result<()> {
    use proc_mounts::MountIter;

    // Check whether `/proc/mounts` exists.
    let mount_iter = match MountIter::new() {
        Ok(mount_iter) => mount_iter,
        Err(_) => {
            // `/proc/mounts` doesn't exist. Try to fall back to `/etc/mtab`.
            MountIter::new_from_file("/etc/mtab").map_err(Error::MissingFile)?
        },
    };

    for mount_info in mount_iter {
        let mount_info = mount_info.map_err(Error::MountInfoParse)?;
        session.reply(Response {
           mount_info,
        })?;
    }

    Ok(())
}

/// Converts filesystem mount option in `String` representation to
/// GRR's `KeyValue` protobuf struct representation.
fn option_to_key_value(option: String) -> rrg_proto::jobs::KeyValue {
    match &option.split('=').collect::<Vec<&str>>()[..] {
        &[key] => rrg_proto::jobs::KeyValue::key(String::from(key)),
        &[key, value] => rrg_proto::jobs::KeyValue::pair(String::from(key), String::from(value)),
        _ => {
            error!("invalid mount option syntax: {}", option);
            // TODO: It's better not to send any key-value in this case.
            rrg_proto::jobs::KeyValue::new()
        },
    }
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("Filesystem");

    type Proto = rrg_proto::sysinfo::Filesystem;

    fn into_proto(self) -> rrg_proto::sysinfo::Filesystem {
        let options: rrg_proto::jobs::AttributedDict = self.mount_info.options.into_iter()
            .map(option_to_key_value)
            .collect();

        // TODO: Remove lossy conversion of `PathBuf` to `String`
        // when `mount_point` and `device` fields of `Filesystem` message
        // will have `bytes` type instead of `string`.
        let mut proto = rrg_proto::sysinfo::Filesystem::new();
        proto.set_device(self.mount_info.source.to_string_lossy().into_owned());
        proto.set_mount_point(self.mount_info.dest.to_string_lossy().into_owned());
        proto.set_field_type(self.mount_info.fstype);
        proto.set_options(options);

        proto
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_if_any_filesystem_exists() {
        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());
        assert_ne!(session.reply_count(), 0);
    }

    #[cfg(feature = "test-fuse")]
    #[test]
    fn test_fuse_filesystem() {
        /// Unit-like struct, representing a filesystem for testing with `fuse`.
        struct FuseFilesystem;

        impl fuse::Filesystem for FuseFilesystem {}

        let fs_name = std::path::PathBuf::from("fuse-test-fs");

        let tmp_dir = tempfile::tempdir().unwrap();
        let mountpoint = tmp_dir.path();

        let fs_name_option = format!("fsname={}", fs_name.to_str().unwrap());
        let options = [
            "-o", "ro",
            "-o", "nosuid",
            "-o", "nodev",
            "-o", "relatime",
            "-o", "subtype=custom-type",
            "-o", &fs_name_option,
        ];
        let options = options.iter().map(|opt| opt.as_ref())
            .collect::<Vec<&std::ffi::OsStr>>();

        // Spawn a background thread to handle filesystem operations.
        // When `_background_session` is dropped, filesystem will be unmounted.
        let background_session = unsafe {
            fuse::spawn_mount(FuseFilesystem, &mountpoint, &options).unwrap()
        };

        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());

        let fuse_mounted_fs = session.replies::<Response>()
            .find(|reply| reply.mount_info.source == fs_name)
            .expect("no reply with a mounted FUSE filesystem");

        let mount_info = &fuse_mounted_fs.mount_info;
        assert_eq!(mount_info.source, fs_name);
        assert_eq!(mount_info.dest, tmp_dir.path());
        assert_eq!(mount_info.fstype, "fuse.custom-type");

        let options = &mount_info.options;
        assert!(options.iter().any(|opt| opt == "ro"));
        assert!(options.iter().any(|opt| opt == "nosuid"));
        assert!(options.iter().any(|opt| opt == "nodev"));
        assert!(options.iter().any(|opt| opt == "relatime"));

        let uid = unsafe { libc::getuid() };
        let gid = unsafe { libc::getgid() };

        // `user_id` and `group_id` are set by libfuse.
        // http://man7.org/linux/man-pages/man8/mount.fuse.8.html
        let current_uid_option = format!("user_id={}", uid);
        assert!(options.iter().any(|opt| *opt == current_uid_option));

        let current_gid_option = format!("group_id={}", gid);
        assert!(options.iter().any(|opt| *opt == current_gid_option));

        drop(background_session);
    }
}
<|endoftext|>


<commit_before>use crate::{render_object::*, utils::Point};

/// The target of the popup, given as an entity or as fixed point coordinate.
#[derive(Clone, Debug, PartialEq)]
pub enum PopupTarget {
    /// the entity of the target (Entity).
    Entity(Entity),

    /// the point coordinate (f64, f64).
    Point(Point),
}

impl Default for PopupTarget {
    fn default() -> Self {
	Self::Point(Point::new(0.0, 0.0))
    }
}

impl From<Entity> for PopupTarget {
    fn from(entity: Entity) -> Self {
	Self::Entity(entity)
    }
}

impl From<Point> for PopupTarget {
    fn from(point: Point) -> Self {
	Self::Point(point)
    }
}

impl IntoPropertySource<PopupTarget> for Entity {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

impl IntoPropertySource<PopupTarget> for Point {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

/// Defines popup placement options relative to its target.
#[derive(Clone, Debug, PartialEq)]
pub enum Placement {
    Bottom,
    Left,
    Right,
    Top,
}

impl Default for Placement {
    fn default() -> Self {
	Self::Bottom
    }
}
impl Placement {
    /// Returns the placement name.
    pub fn get_name(&self, index: i32) -> String {
	match index {
	    0 => "Bottom".to_string(),
	    1 => "Left".to_string(),
	    2 => "Right".to_string(),
	    3 => "Top".to_string(),
	    _ => {
		eprintln!("popup: placement variant with index {} not coverd!", index);
		std::process::exit(1);
	    }
	}
    }

    /// Returns the placement index.
    pub fn get_index(&self, string: &str) -> u32 {
	match string {
	    "Bottom" => 0,
	    "Left" => 1,
	    "Right" => 2,
	    "Top" => 3,
	    _ => {
		eprintln!("popup: placement variant {} not coverd!", string);
		std::process::exit(1);
	    }
	}
    }

    /// Place the popup widget relative to the `bottom` of its parent target.
    pub fn bottom(self) -> Self {
	Self::Bottom
    }

    /// Place the popup widget relative to the left of its parent target.
    pub fn left(self) -> Self {
	Self::Left
    }

    /// Place the popup widget relative to the `right` of its parent target.
    pub fn right(self) -> Self {
	Self::Right
    }
    /// Place the popup widget relative to the `top` of its parent target.
    pub fn top(self) -> Self {
	Self::Top
    }
}

into_property_source!(Placement);

/// The `PopupRenderObject` is used to render the contents of a `Popup` widget inside a recangle.
pub struct PopupRenderObject(RectangleRenderObject);

impl PopupRenderObject {
    pub fn new() -> Self {
	Self::default()
    }
}
impl Default for PopupRenderObject {
    fn default() -> Self {
	Self(RectangleRenderObject)
    }
}

impl Into<Box<dyn RenderObject>> for PopupRenderObject {
    fn into(self) -> Box<dyn RenderObject> {
	Box::new(self)
    }
}

impl RenderObject for PopupRenderObject {
    fn render_self(&self, ctx: &mut Context, global_position: &Point) {
	if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {
	    let current_bounds: Rectangle = ctx.widget().clone("bounds");
	    let current_constraint: Constraint = ctx.widget().clone("constraint");

	    let target_bounds = match target {
		PopupTarget::Entity(entity) => {
		    let target_position: Point = ctx.get_widget(entity).clone("position");

		    // WARNING: target_bounds are only reflecting the
		    // actual effective size, if refered in
		    // post_layout_update function. Otherwise the
		    // bounds will refere to the space bounds
		    // available to the given widget.
		    let mut target_bounds: Rectangle = ctx.get_widget(entity).clone("bounds");
		    target_bounds.set_position(target_position);
		    target_bounds
		}
		PopupTarget::Point(mut point) => {
		    point.set_x(point.x() + current_bounds.width() / 2.0);
		    point.set_y(point.y() + current_bounds.height() / 2.0);
		    Rectangle::new(point, (0.0, 0.0))
		}
	    };

	    let placement: Placement = ctx.widget().clone_or_default("placement");
	    let offset: f64 = ctx.widget().clone_or_default("offset");

	    let new_popup_bounds = match placement {
		Placement::Bottom => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() + target_bounds.height() + offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Left => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() - current_bounds.width() - offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Right => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() + target_bounds.width() + offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Top => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() - current_bounds.height() - offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
	    };

	    ctx.widget().set::<Rectangle>("bounds", new_popup_bounds);
	} else {
	    println!("Target not found");
	}

	self.0.render_self(ctx, global_position);
    }
}
<commit_msg>orbtk_core: impl From<PopupRenderObject> for popup render_object<commit_after>use crate::{render_object::*, utils::Point};

/// The target of the popup, given as an entity or as fixed point coordinate.
#[derive(Clone, Debug, PartialEq)]
pub enum PopupTarget {
    /// the entity of the target (Entity).
    Entity(Entity),

    /// the point coordinate (f64, f64).
    Point(Point),
}

impl Default for PopupTarget {
    fn default() -> Self {
	Self::Point(Point::new(0.0, 0.0))
    }
}

impl From<Entity> for PopupTarget {
    fn from(entity: Entity) -> Self {
	Self::Entity(entity)
    }
}

impl From<Point> for PopupTarget {
    fn from(point: Point) -> Self {
	Self::Point(point)
    }
}

impl IntoPropertySource<PopupTarget> for Entity {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

impl IntoPropertySource<PopupTarget> for Point {
    fn into_source(self) -> PropertySource<PopupTarget> {
	PropertySource::Value(self.into())
    }
}

/// Defines popup placement options relative to its target.
#[derive(Clone, Debug, PartialEq)]
pub enum Placement {
    Bottom,
    Left,
    Right,
    Top,
}

impl Default for Placement {
    fn default() -> Self {
	Self::Bottom
    }
}
impl Placement {
    /// Returns the placement name.
    pub fn get_name(&self, index: i32) -> String {
	match index {
	    0 => "Bottom".to_string(),
	    1 => "Left".to_string(),
	    2 => "Right".to_string(),
	    3 => "Top".to_string(),
	    _ => {
		eprintln!("popup: placement variant with index {} not coverd!", index);
		std::process::exit(1);
	    }
	}
    }

    /// Returns the placement index.
    pub fn get_index(&self, string: &str) -> u32 {
	match string {
	    "Bottom" => 0,
	    "Left" => 1,
	    "Right" => 2,
	    "Top" => 3,
	    _ => {
		eprintln!("popup: placement variant {} not coverd!", string);
		std::process::exit(1);
	    }
	}
    }

    /// Place the popup widget relative to the `bottom` of its parent target.
    pub fn bottom(self) -> Self {
	Self::Bottom
    }

    /// Place the popup widget relative to the left of its parent target.
    pub fn left(self) -> Self {
	Self::Left
    }

    /// Place the popup widget relative to the `right` of its parent target.
    pub fn right(self) -> Self {
	Self::Right
    }
    /// Place the popup widget relative to the `top` of its parent target.
    pub fn top(self) -> Self {
	Self::Top
    }
}

into_property_source!(Placement);

/// The `PopupRenderObject` is used to render the contents of a `Popup` widget inside a recangle.
pub struct PopupRenderObject(RectangleRenderObject);

impl PopupRenderObject {
    pub fn new() -> Self {
	Self::default()
    }
}
impl Default for PopupRenderObject {
    fn default() -> Self {
	Self(RectangleRenderObject)
    }
}

impl From<PopupRenderObject> for Box<dyn RenderObject>  {
    fn from(box_value: PopupRenderObject) -> Self {
	Box::new(box_value)
    }
}

impl RenderObject for PopupRenderObject {
    fn render_self(&self, ctx: &mut Context, global_position: &Point) {
	if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {
	    let current_bounds: Rectangle = ctx.widget().clone("bounds");
	    let current_constraint: Constraint = ctx.widget().clone("constraint");

	    let target_bounds = match target {
		PopupTarget::Entity(entity) => {
		    let target_position: Point = ctx.get_widget(entity).clone("position");

		    // WARNING: target_bounds are only reflecting the
		    // actual effective size, if refered in
		    // post_layout_update function. Otherwise the
		    // bounds will refere to the space bounds
		    // available to the given widget.
		    let mut target_bounds: Rectangle = ctx.get_widget(entity).clone("bounds");
		    target_bounds.set_position(target_position);
		    target_bounds
		}
		PopupTarget::Point(mut point) => {
		    point.set_x(point.x() + current_bounds.width() / 2.0);
		    point.set_y(point.y() + current_bounds.height() / 2.0);
		    Rectangle::new(point, (0.0, 0.0))
		}
	    };

	    let placement: Placement = ctx.widget().clone_or_default("placement");
	    let offset: f64 = ctx.widget().clone_or_default("offset");

	    let new_popup_bounds = match placement {
		Placement::Bottom => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() + target_bounds.height() + offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Left => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() - current_bounds.width() - offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Right => {
		    let current_v_align: Alignment = ctx.widget().clone("v_align");

		    let x = target_bounds.x() + target_bounds.width() + offset;
		    let y = current_v_align.align_position(
			target_bounds.height(),
			current_bounds.height(),
			target_bounds.y(),
			target_bounds.y() + target_bounds.height(),
		    );

		    let width = current_bounds.width();
		    let height = current_v_align.align_measure(
			target_bounds.height(),
			current_bounds.height(),
			0.0,
			0.0,
		    );

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
		Placement::Top => {
		    let current_h_align: Alignment = ctx.widget().clone("h_align");

		    let x = current_h_align.align_position(
			target_bounds.width(),
			current_bounds.width(),
			target_bounds.x(),
			target_bounds.x() + target_bounds.width(),
		    );
		    let y = target_bounds.y() - current_bounds.height() - offset;
		    let width = current_h_align.align_measure(
			target_bounds.width(),
			current_bounds.width(),
			0.0,
			0.0,
		    );
		    let height = current_bounds.height();

		    Rectangle::new((x, y), current_constraint.perform((width, height)))
		}
	    };

	    ctx.widget().set::<Rectangle>("bounds", new_popup_bounds);
	} else {
	    println!("Target not found");
	}

	self.0.render_self(ctx, global_position);
    }
}
<|endoftext|>


<commit_before>use super::internal_prelude::*;

pub static FLIP_V_PRIMITIVE: FlipVerticalMutNodeDef = FlipVerticalMutNodeDef{} ;
pub static FLIP_H_PRIMITIVE: FlipHorizontalMutNodeDef = FlipHorizontalMutNodeDef{};
pub static FLIP_V: MutProtect<FlipVerticalMutNodeDef> = MutProtect{ node: &FLIP_V_PRIMITIVE, fqn: "imazen.flip_vertical"};
pub static FLIP_H: MutProtect<FlipHorizontalMutNodeDef> = MutProtect{ node: &FLIP_H_PRIMITIVE, fqn: "imazen.flip_horizontal"};
pub static APPLY_ORIENTATION: ApplyOrientationDef = ApplyOrientationDef{};
pub static NO_OP: NoOpDef = NoOpDef{};
pub static ROTATE_90: Rotate90Def = Rotate90Def{};
pub static ROTATE_180: Rotate180Def = Rotate180Def{};
pub static ROTATE_270: Rotate270Def = Rotate270Def{};
pub static TRANSPOSE: TransposeDef = TransposeDef{};
pub static TRANSPOSE_MUT: TransposeMutDef = TransposeMutDef{};

#[derive(Debug,Clone)]
pub struct ApplyOrientationDef;
impl NodeDef for ApplyOrientationDef{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for ApplyOrientationDef{
    fn fqn(&self) -> &'static str{
        "imazen.apply_orientation"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        if let NodeParams::Json(s::Node::ApplyOrientation { flag }) = *p {
            input.map_frame(|info| {
                let swap = flag >= 5 && flag <= 8;
                Ok(FrameInfo {
                    w: if swap {
                        info.h
                    } else { info.w },
                    h: if swap {
                        info.w
                    } else { info.h },
                    ..info
                })
            })
        } else {
            Err(nerror!(crate::ErrorKind::NodeParamsMismatch, "Need ApplyOrientation, got {:?}", p))
        }
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()>{
        if let NodeParams::Json(s::Node::ApplyOrientation { flag }) = p {
            let replacement_nodes: Vec<&'static dyn NodeDef> = match flag {
                7 => vec![&ROTATE_180, &TRANSPOSE],
                8 => vec![&ROTATE_90],
                6 => vec![&ROTATE_270],
                5 => vec![&TRANSPOSE],
                4 => vec![&FLIP_V],
                3 => vec![&ROTATE_180],
                2 => vec![&FLIP_H],
                _ => vec![],
            };
            ctx.replace_node(ix,
                             replacement_nodes.iter()
                                 .map(|v| Node::n(*v, NodeParams::None))
                                 .collect());
            Ok(())
        } else {
            Err(nerror!(crate::ErrorKind::NodeParamsMismatch, "Need ApplyOrientation, got {:?}", p))
        }
    }
}

#[derive(Debug,Clone)]
pub struct TransposeDef;
impl NodeDef for TransposeDef{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for TransposeDef {
    fn fqn(&self) -> &'static str {
        "imazen.transpose"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input.transpose())
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        let canvas_params = s::Node::CreateCanvas {
            w: parent.h as usize,
            h: parent.w as usize,
            format: s::PixelFormat::from(parent.fmt),
            color: s::Color::Transparent,
        };
        let canvas = ctx.graph
            .add_node(Node::n(&CREATE_CANVAS,
                              NodeParams::Json(canvas_params)));
        let copy = ctx.graph
            .add_node(Node::n(&TRANSPOSE_MUT, NodeParams::None));
        ctx.graph.add_edge(canvas, copy, EdgeKind::Canvas).unwrap();
        ctx.replace_node_with_existing(ix, copy);
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct NoOpDef;
impl NodeDef for NoOpDef{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for NoOpDef {
    fn fqn(&self) -> &'static str {
        "imazen.noop"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input)
    }
    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix, vec![]);
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct TransposeMutDef;

impl NodeDef for TransposeMutDef {
    fn as_one_input_one_canvas(&self) -> Option<&dyn NodeDefOneInputOneCanvas> {
        Some(self)
    }
}

impl NodeDefOneInputOneCanvas for TransposeMutDef {
    fn fqn(&self) -> &'static str {
        "imazen.transpose_mut"
    }
    fn validate_params(&self, p: &NodeParams) -> Result<()> {
        Ok(())
    }

    fn render(&self, c: &Context, canvas_key: BitmapKey, input_key: BitmapKey, p: &NodeParams) -> Result<()> {
        unsafe {
            if input_key == canvas_key {
                panic!("Canvas and input must be different bitmaps for transpose to work!")
            }

            let bitmaps = c.borrow_bitmaps()
                .map_err(|e| e.at(here!()))?;
            let mut canvas_bitmap = bitmaps.try_borrow_mut(canvas_key)
                .map_err(|e| e.at(here!()))?;
            let mut canvas_bgra = canvas_bitmap.get_window_u8().unwrap()
                .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            let mut input_bitmap = bitmaps.try_borrow_mut(input_key)
                .map_err(|e| e.at(here!()))?;
            let mut input_bgra = input_bitmap.get_window_u8().unwrap()
                .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            if input_bgra.fmt != canvas_bgra.fmt {
                panic!("Can't copy between bitmaps with different pixel formats")
            }

            crate::graphics::transpose::flow_bitmap_bgra_transpose(&mut input_bgra, &mut canvas_bgra)
                .map_err(|e| e.at(here!()))?;
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct FlipVerticalMutNodeDef;
impl NodeDef for FlipVerticalMutNodeDef{
    fn as_one_mutate_bitmap(&self) -> Option<&dyn NodeDefMutateBitmap>{
        Some(self)
    }
}
impl NodeDefMutateBitmap for FlipVerticalMutNodeDef{
    fn fqn(&self) -> &'static str{
        "imazen.flip_vertical_mutate"
    }
    fn mutate(&self, c: &Context, bitmap_key: BitmapKey,  p: &NodeParams) -> Result<()>{
        unsafe {
            let bitmaps = c.borrow_bitmaps()
                .map_err(|e| e.at(here!()))?;
            let mut bitmap = bitmaps.try_borrow_mut(bitmap_key)
                .map_err(|e| e.at(here!()))?;

            let mut bitmap_bgra = bitmap.get_window_u8().unwrap()
                .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            crate::graphics::flip::flow_bitmap_bgra_flip_vertical(&mut bitmap_bgra)
                .map_err(|e| e.at(here!()))?;

        }
        Ok(())
    }
}
#[derive(Debug, Clone)]
pub struct FlipHorizontalMutNodeDef;
impl NodeDef for FlipHorizontalMutNodeDef{
    fn as_one_mutate_bitmap(&self) -> Option<&dyn NodeDefMutateBitmap>{
        Some(self)
    }
}
impl NodeDefMutateBitmap for FlipHorizontalMutNodeDef{
    fn fqn(&self) -> &'static str{
        "imazen.flip_vertical_mutate"
    }
    fn mutate(&self, c: &Context, bitmap_key: BitmapKey,  p: &NodeParams) -> Result<()>{
        unsafe {

            let bitmaps = c.borrow_bitmaps()
                .map_err(|e| e.at(here!()))?;
            let mut bitmap = bitmaps.try_borrow_mut(bitmap_key)
                .map_err(|e| e.at(here!()))?;

            let mut bitmap_bgra = bitmap.get_window_u8().unwrap()
                    .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            crate::graphics::flip::flow_bitmap_bgra_flip_horizontal(&mut bitmap_bgra)
                .map_err(|e| e.at(here!()))?;

        }
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct Rotate90Def;
impl NodeDef for Rotate90Def{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for Rotate90Def {
    fn fqn(&self) -> &'static str {
        "imazen.rotate_90"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input.transpose())
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix,
                         vec![
                             Node::n(&FLIP_V, NodeParams::None),
                             Node::n(&TRANSPOSE, NodeParams::None)
                         ]);
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct Rotate270Def;
impl NodeDef for Rotate270Def{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for Rotate270Def {
    fn fqn(&self) -> &'static str {
        "imazen.rotate_270"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input.transpose())
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix,
                         vec![
                             Node::n(&TRANSPOSE, NodeParams::None),
                             Node::n(&FLIP_V, NodeParams::None),
                         ]);
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct Rotate180Def;
impl NodeDef for Rotate180Def{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for Rotate180Def {
    fn fqn(&self) -> &'static str {
        "imazen.rotate_180"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input)
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix,
                         vec![
                             Node::n(&FLIP_V as &dyn NodeDef, NodeParams::None),
                             Node::n(&FLIP_H, NodeParams::None),
                         ]);
        Ok(())
    }
}
<commit_msg>Fix JPEG Exif orientation to work with clockwise rotations<commit_after>use super::internal_prelude::*;

pub static FLIP_V_PRIMITIVE: FlipVerticalMutNodeDef = FlipVerticalMutNodeDef{} ;
pub static FLIP_H_PRIMITIVE: FlipHorizontalMutNodeDef = FlipHorizontalMutNodeDef{};
pub static FLIP_V: MutProtect<FlipVerticalMutNodeDef> = MutProtect{ node: &FLIP_V_PRIMITIVE, fqn: "imazen.flip_vertical"};
pub static FLIP_H: MutProtect<FlipHorizontalMutNodeDef> = MutProtect{ node: &FLIP_H_PRIMITIVE, fqn: "imazen.flip_horizontal"};
pub static APPLY_ORIENTATION: ApplyOrientationDef = ApplyOrientationDef{};
pub static NO_OP: NoOpDef = NoOpDef{};
pub static ROTATE_90: Rotate90Def = Rotate90Def{};
pub static ROTATE_180: Rotate180Def = Rotate180Def{};
pub static ROTATE_270: Rotate270Def = Rotate270Def{};
pub static TRANSPOSE: TransposeDef = TransposeDef{};
pub static TRANSPOSE_MUT: TransposeMutDef = TransposeMutDef{};

#[derive(Debug,Clone)]
pub struct ApplyOrientationDef;
impl NodeDef for ApplyOrientationDef{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for ApplyOrientationDef{
    fn fqn(&self) -> &'static str{
        "imazen.apply_orientation"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        if let NodeParams::Json(s::Node::ApplyOrientation { flag }) = *p {
            input.map_frame(|info| {
                let swap = flag >= 5 && flag <= 8;
                Ok(FrameInfo {
                    w: if swap {
                        info.h
                    } else { info.w },
                    h: if swap {
                        info.w
                    } else { info.h },
                    ..info
                })
            })
        } else {
            Err(nerror!(crate::ErrorKind::NodeParamsMismatch, "Need ApplyOrientation, got {:?}", p))
        }
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()>{
        if let NodeParams::Json(s::Node::ApplyOrientation { flag }) = p {
            let replacement_nodes: Vec<&'static dyn NodeDef> = match flag {
                7 => vec![&ROTATE_180, &TRANSPOSE],
                8 => vec![&ROTATE_270],
                6 => vec![&ROTATE_90],
                5 => vec![&TRANSPOSE],
                4 => vec![&FLIP_V],
                3 => vec![&ROTATE_180],
                2 => vec![&FLIP_H],
                _ => vec![],
            };
            ctx.replace_node(ix,
                             replacement_nodes.iter()
                                 .map(|v| Node::n(*v, NodeParams::None))
                                 .collect());
            Ok(())
        } else {
            Err(nerror!(crate::ErrorKind::NodeParamsMismatch, "Need ApplyOrientation, got {:?}", p))
        }
    }
}

#[derive(Debug,Clone)]
pub struct TransposeDef;
impl NodeDef for TransposeDef{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for TransposeDef {
    fn fqn(&self) -> &'static str {
        "imazen.transpose"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input.transpose())
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        let canvas_params = s::Node::CreateCanvas {
            w: parent.h as usize,
            h: parent.w as usize,
            format: s::PixelFormat::from(parent.fmt),
            color: s::Color::Transparent,
        };
        let canvas = ctx.graph
            .add_node(Node::n(&CREATE_CANVAS,
                              NodeParams::Json(canvas_params)));
        let copy = ctx.graph
            .add_node(Node::n(&TRANSPOSE_MUT, NodeParams::None));
        ctx.graph.add_edge(canvas, copy, EdgeKind::Canvas).unwrap();
        ctx.replace_node_with_existing(ix, copy);
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct NoOpDef;
impl NodeDef for NoOpDef{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for NoOpDef {
    fn fqn(&self) -> &'static str {
        "imazen.noop"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input)
    }
    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix, vec![]);
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct TransposeMutDef;

impl NodeDef for TransposeMutDef {
    fn as_one_input_one_canvas(&self) -> Option<&dyn NodeDefOneInputOneCanvas> {
        Some(self)
    }
}

impl NodeDefOneInputOneCanvas for TransposeMutDef {
    fn fqn(&self) -> &'static str {
        "imazen.transpose_mut"
    }
    fn validate_params(&self, p: &NodeParams) -> Result<()> {
        Ok(())
    }

    fn render(&self, c: &Context, canvas_key: BitmapKey, input_key: BitmapKey, p: &NodeParams) -> Result<()> {
        unsafe {
            if input_key == canvas_key {
                panic!("Canvas and input must be different bitmaps for transpose to work!")
            }

            let bitmaps = c.borrow_bitmaps()
                .map_err(|e| e.at(here!()))?;
            let mut canvas_bitmap = bitmaps.try_borrow_mut(canvas_key)
                .map_err(|e| e.at(here!()))?;
            let mut canvas_bgra = canvas_bitmap.get_window_u8().unwrap()
                .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            let mut input_bitmap = bitmaps.try_borrow_mut(input_key)
                .map_err(|e| e.at(here!()))?;
            let mut input_bgra = input_bitmap.get_window_u8().unwrap()
                .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            if input_bgra.fmt != canvas_bgra.fmt {
                panic!("Can't copy between bitmaps with different pixel formats")
            }

            crate::graphics::transpose::flow_bitmap_bgra_transpose(&mut input_bgra, &mut canvas_bgra)
                .map_err(|e| e.at(here!()))?;
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct FlipVerticalMutNodeDef;
impl NodeDef for FlipVerticalMutNodeDef{
    fn as_one_mutate_bitmap(&self) -> Option<&dyn NodeDefMutateBitmap>{
        Some(self)
    }
}
impl NodeDefMutateBitmap for FlipVerticalMutNodeDef{
    fn fqn(&self) -> &'static str{
        "imazen.flip_vertical_mutate"
    }
    fn mutate(&self, c: &Context, bitmap_key: BitmapKey,  p: &NodeParams) -> Result<()>{
        unsafe {
            let bitmaps = c.borrow_bitmaps()
                .map_err(|e| e.at(here!()))?;
            let mut bitmap = bitmaps.try_borrow_mut(bitmap_key)
                .map_err(|e| e.at(here!()))?;

            let mut bitmap_bgra = bitmap.get_window_u8().unwrap()
                .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            crate::graphics::flip::flow_bitmap_bgra_flip_vertical(&mut bitmap_bgra)
                .map_err(|e| e.at(here!()))?;

        }
        Ok(())
    }
}
#[derive(Debug, Clone)]
pub struct FlipHorizontalMutNodeDef;
impl NodeDef for FlipHorizontalMutNodeDef{
    fn as_one_mutate_bitmap(&self) -> Option<&dyn NodeDefMutateBitmap>{
        Some(self)
    }
}
impl NodeDefMutateBitmap for FlipHorizontalMutNodeDef{
    fn fqn(&self) -> &'static str{
        "imazen.flip_vertical_mutate"
    }
    fn mutate(&self, c: &Context, bitmap_key: BitmapKey,  p: &NodeParams) -> Result<()>{
        unsafe {

            let bitmaps = c.borrow_bitmaps()
                .map_err(|e| e.at(here!()))?;
            let mut bitmap = bitmaps.try_borrow_mut(bitmap_key)
                .map_err(|e| e.at(here!()))?;

            let mut bitmap_bgra = bitmap.get_window_u8().unwrap()
                    .to_bitmap_bgra().map_err(|e| e.at(here!()))?;

            crate::graphics::flip::flow_bitmap_bgra_flip_horizontal(&mut bitmap_bgra)
                .map_err(|e| e.at(here!()))?;

        }
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct Rotate90Def;
impl NodeDef for Rotate90Def{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for Rotate90Def {
    fn fqn(&self) -> &'static str {
        "imazen.rotate_90"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input.transpose())
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix,
                         vec![
                             Node::n(&FLIP_V, NodeParams::None),
                             Node::n(&TRANSPOSE, NodeParams::None)
                         ]);
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct Rotate270Def;
impl NodeDef for Rotate270Def{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for Rotate270Def {
    fn fqn(&self) -> &'static str {
        "imazen.rotate_270"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input.transpose())
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix,
                         vec![
                             Node::n(&TRANSPOSE, NodeParams::None),
                             Node::n(&FLIP_V, NodeParams::None),
                         ]);
        Ok(())
    }
}

#[derive(Debug,Clone)]
pub struct Rotate180Def;
impl NodeDef for Rotate180Def{
    fn as_one_input_expand(&self) -> Option<&dyn NodeDefOneInputExpand>{
        Some(self)
    }
}
impl NodeDefOneInputExpand for Rotate180Def {
    fn fqn(&self) -> &'static str {
        "imazen.rotate_180"
    }
    fn estimate(&self, p: &NodeParams, input: FrameEstimate) -> Result<FrameEstimate> {
        Ok(input)
    }

    fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, p: NodeParams, parent: FrameInfo) -> Result<()> {
        ctx.replace_node(ix,
                         vec![
                             Node::n(&FLIP_V as &dyn NodeDef, NodeParams::None),
                             Node::n(&FLIP_H, NodeParams::None),
                         ]);
        Ok(())
    }
}
<|endoftext|>


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

use crate::i8042;
use core::ops::Deref;
use lazy_static::lazy_static;
use log::error;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};

lazy_static! {
    static ref IDT: InterruptDescriptorTable = {
        let mut idt = InterruptDescriptorTable::new();
        idt.double_fault.set_handler_fn(double_fault_handler);
        idt.breakpoint.set_handler_fn(breakpoint_handler);
        idt
    };
}

extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
    log::error!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}

extern "x86-interrupt" fn double_fault_handler(
    stack_frame: InterruptStackFrame,
    _error_code: u64,
) -> ! {
    // We're not calling `panic!` here because (a) the panic location would be all wrong (the error
    // is not in the fault handler itself as the location would suggest), (b) in theory the
    // panic handler itself could cause a double fault, and (c) we want to be sure that we shut
    // down the machine after us.
    // Note that for double fault handlers the error code will always be 0, so there's no point in
    // logging that.
    error!("KERNEL PANIC: DOUBLE FAULT");
    error!(
        "Instruction pointer: {:#016x}",
        stack_frame.deref().instruction_pointer.as_u64()
    );
    error!("Code segment: {:#x}", stack_frame.deref().code_segment);
    error!(
        "Stack pointer: {:#016x}",
        stack_frame.deref().stack_pointer.as_u64()
    );
    error!("Stack segment: {:#x}", stack_frame.deref().stack_segment);
    error!("CPU flags: {:#x}", stack_frame.deref().cpu_flags);
    i8042::shutdown();
}

pub fn init_idt() {
    IDT.load();
}
<commit_msg>Add a page fault handler in addition to double fault handler.<commit_after>//
// Copyright 2022 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use crate::i8042;
use core::ops::Deref;
use lazy_static::lazy_static;
use log::error;
use x86_64::{
    registers::control::Cr2,
    structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
};

lazy_static! {
    static ref IDT: InterruptDescriptorTable = {
        let mut idt = InterruptDescriptorTable::new();
        idt.double_fault.set_handler_fn(double_fault_handler);
        idt.page_fault.set_handler_fn(page_fault_handler);
        idt.breakpoint.set_handler_fn(breakpoint_handler);
        idt
    };
}

extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
    log::error!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}

extern "x86-interrupt" fn page_fault_handler(
    stack_frame: InterruptStackFrame,
    error_code: PageFaultErrorCode,
) {
    error!("KERNEL PANIC: PAGE FAULT");
    error!(
        "Instruction pointer: {:#016x}",
        stack_frame.deref().instruction_pointer.as_u64()
    );
    error!("Faulting virtual address: {:#018x}", Cr2::read());
    error!("Error code: {:?}", error_code);
    i8042::shutdown();
}

extern "x86-interrupt" fn double_fault_handler(
    stack_frame: InterruptStackFrame,
    _error_code: u64,
) -> ! {
    // We're not calling `panic!` here because (a) the panic location would be all wrong (the error
    // is not in the fault handler itself as the location would suggest), (b) in theory the
    // panic handler itself could cause a double fault, and (c) we want to be sure that we shut
    // down the machine after us.
    // Note that for double fault handlers the error code will always be 0, so there's no point in
    // logging that.
    error!("KERNEL PANIC: DOUBLE FAULT");
    error!(
        "Instruction pointer: {:#016x}",
        stack_frame.deref().instruction_pointer.as_u64()
    );
    error!("Code segment: {:#x}", stack_frame.deref().code_segment);
    error!(
        "Stack pointer: {:#016x}",
        stack_frame.deref().stack_pointer.as_u64()
    );
    error!("Stack segment: {:#x}", stack_frame.deref().stack_segment);
    error!("CPU flags: {:#x}", stack_frame.deref().cpu_flags);
    i8042::shutdown();
}

pub fn init_idt() {
    IDT.load();
}
<|endoftext|>


<commit_before>extern crate graphics;
extern crate opengl_graphics;
extern crate image;
extern crate piston;
extern crate sdl2_window;

use std::path::Path;
use opengl_graphics::{GlGraphics, Texture};
use piston::event_loop::*;
use piston::input::*;
use piston::window::WindowSettings;
use sdl2_window::{Sdl2Window, OpenGL};
use graphics::draw_state::Blend;

fn main() {
    println!("Press A to change blending");
    println!("Press S to change clip inside/out");

    let opengl = OpenGL::V3_2;
    let (w, h) = (640, 480);
    let mut window: Sdl2Window = WindowSettings::new("opengl_graphics: draw_state", [w, h])
        .exit_on_esc(true)
        .build()
        .unwrap();

    let mut clip_inside = true;
    let blends = [Blend::Alpha, Blend::Add, Blend::Invert, Blend::Multiply];
    let mut blend = 0;
    let rust_logo = Texture::from_path(&Path::new("./assets/rust.png")).unwrap();
    let mut gl = GlGraphics::new(opengl);
    let mut events = Events::new(EventSettings::new().lazy(true));
    while let Some(e) = events.next(&mut window) {
        if let Some(args) = e.render_args() {
            use graphics::*;

            gl.draw(args.viewport(), |c, g| {
                clear([0.8, 0.8, 0.8, 1.0], g);
                Rectangle::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 100.0, 100.0], &c.draw_state, c.transform, g);

                let draw_state = c.draw_state.blend(blends[blend]);
                Rectangle::new([0.5, 1.0, 0.0, 0.3])
                    .draw([50.0, 50.0, 100.0, 100.0], &draw_state, c.transform, g);

                let transform = c.transform.trans(100.0, 100.0);
                // Compute clip rectangle from upper left corner.
                let (clip_x, clip_y, clip_w, clip_h) = (100, 100, 100, 100);
                let (clip_x, clip_y, clip_w, clip_h) =
                    (clip_x, c.viewport.unwrap().draw_size[1] - clip_y - clip_h, clip_w, clip_h);
                let clipped = c.draw_state.scissor([clip_x, clip_y, clip_w, clip_h]);
                Image::new().draw(&rust_logo, &clipped, transform, g);

                let transform = c.transform.trans(200.0, 200.0);
                Ellipse::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 50.0, 50.0], &DrawState::new_clip(), transform, g);
                Image::new().draw(&rust_logo,
                                  &if clip_inside {
                                      DrawState::new_inside()
                                  } else {
                                      DrawState::new_outside()
                                  },
                                  transform,
                                  g);
            });
        }

        if let Some(Button::Keyboard(Key::A)) = e.press_args() {
            blend = (blend + 1) % blends.len();
            println!("Changed blending to {:?}", blends[blend]);
        }

        if let Some(Button::Keyboard(Key::S)) = e.press_args() {
            clip_inside = !clip_inside;
            if clip_inside {
                println!("Changed to clip inside");
            } else {
                println!("Changed to clip outside");
            }
        }
    }
}
<commit_msg>Use version given in opengl variable when creating window<commit_after>extern crate graphics;
extern crate opengl_graphics;
extern crate image;
extern crate piston;
extern crate sdl2_window;

use std::path::Path;
use opengl_graphics::{GlGraphics, Texture};
use piston::event_loop::*;
use piston::input::*;
use piston::window::WindowSettings;
use sdl2_window::{Sdl2Window, OpenGL};
use graphics::draw_state::Blend;

fn main() {
    println!("Press A to change blending");
    println!("Press S to change clip inside/out");

    let opengl = OpenGL::V3_2;
    let (w, h) = (640, 480);
    let mut window: Sdl2Window = WindowSettings::new("opengl_graphics: draw_state", [w, h])
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap();

    let mut clip_inside = true;
    let blends = [Blend::Alpha, Blend::Add, Blend::Invert, Blend::Multiply];
    let mut blend = 0;
    let rust_logo = Texture::from_path(&Path::new("./assets/rust.png")).unwrap();
    let mut gl = GlGraphics::new(opengl);
    let mut events = Events::new(EventSettings::new().lazy(true));
    while let Some(e) = events.next(&mut window) {
        if let Some(args) = e.render_args() {
            use graphics::*;

            gl.draw(args.viewport(), |c, g| {
                clear([0.8, 0.8, 0.8, 1.0], g);
                Rectangle::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 100.0, 100.0], &c.draw_state, c.transform, g);

                let draw_state = c.draw_state.blend(blends[blend]);
                Rectangle::new([0.5, 1.0, 0.0, 0.3])
                    .draw([50.0, 50.0, 100.0, 100.0], &draw_state, c.transform, g);

                let transform = c.transform.trans(100.0, 100.0);
                // Compute clip rectangle from upper left corner.
                let (clip_x, clip_y, clip_w, clip_h) = (100, 100, 100, 100);
                let (clip_x, clip_y, clip_w, clip_h) =
                    (clip_x, c.viewport.unwrap().draw_size[1] - clip_y - clip_h, clip_w, clip_h);
                let clipped = c.draw_state.scissor([clip_x, clip_y, clip_w, clip_h]);
                Image::new().draw(&rust_logo, &clipped, transform, g);

                let transform = c.transform.trans(200.0, 200.0);
                Ellipse::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 50.0, 50.0], &DrawState::new_clip(), transform, g);
                Image::new().draw(&rust_logo,
                                  &if clip_inside {
                                      DrawState::new_inside()
                                  } else {
                                      DrawState::new_outside()
                                  },
                                  transform,
                                  g);
            });
        }

        if let Some(Button::Keyboard(Key::A)) = e.press_args() {
            blend = (blend + 1) % blends.len();
            println!("Changed blending to {:?}", blends[blend]);
        }

        if let Some(Button::Keyboard(Key::S)) = e.press_args() {
            clip_inside = !clip_inside;
            if clip_inside {
                println!("Changed to clip inside");
            } else {
                println!("Changed to clip outside");
            }
        }
    }
}
<|endoftext|>