<commit_before>use clippy_utils::{diagnostics::{span_lint_and_help, span_lint_and_then, span_lint_and_sugg}, source::{indent_of, snippet}};
use rustc_ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::Const;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// ### What it does
    /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
    ///
    /// ### Why is this bad?
    /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
    ///
    /// ### Example
    /// ```rust
    /// struct RarelyUseful {
    ///     some_field: usize,
    ///     last: [SomeType; 0],
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust
    /// #[repr(C)]
    /// struct MoreOftenUseful {
    ///     some_field: usize,
    ///     last: [SomeType; 0],
    /// }
    /// ```
    pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
    nursery,
    "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
}
declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR]);

impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
        if is_struct_with_trailing_zero_sized_array(cx, item) {
            // NOTE: This is to include attributes on the definition when we print the lint. If the convention
            // is to not do that with struct definitions (I'm not sure), then this isn't necessary. (note: if
            // you don't get rid of this, change `has_repr_attr` to `includes_repr_attr`).
            let attrs = cx.tcx.get_attrs(item.def_id.to_def_id());
            let first_attr = attrs.iter().min_by_key(|attr| attr.span.lo());
            let lint_span = if let Some(first_attr) = first_attr {
                first_attr.span.to(item.span)
            } else {
                item.span
            };

            if !has_repr_attr(cx, attrs) {
                let suggestion_span = item.span.shrink_to_lo();
                let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));

                span_lint_and_sugg(cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", "consider adding `#[repr(C)]` or another `repr` attribute", format!("#[repr(C)]\n{}", snippet(cx, item.span.shrink_to_lo().to(item.ident.span), "..")), Applicability::MaybeIncorrect);

                // span_lint_and_then(
                //     cx,
                //     TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
                //     item.span,
                //     "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
                //     |diag| {
                //         let sugg = format!("#[repr(C)]\n{}", indent);
                //         let sugg2 = format!("#[repr(C)]\n{}", item.ident.span);
                //         diag.span_suggestion(item.span,
                //                               "consider adding `#[repr(C)]` or another `repr` attribute",
                //                               sugg2,
                //                               Applicability::MaybeIncorrect);
                //     }
                // );

                // span_lint_and_help(
                //     cx,
                //     TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
                //     lint_span,
                //     "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
                //     None,
                //     "consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute",
                // );
            }
        }
    }
}

fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
    // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer
    // doesn't work when it's an `if_chain`.

    // First check if last field is an array
    if let ItemKind::Struct(data, _) = &item.kind {
        if let Some(last_field) = data.fields().last() {
            if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind {
                // Then check if that that array zero-sized
                let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
                let length = Const::from_anon_const(cx.tcx, length_ldid);
                let length = length.try_eval_usize(cx.tcx, cx.param_env);
                length == Some(0)
            } else {
                false
            }
        } else {
            false
        }
    } else {
        false
    }
}

fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool {
    // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed
    // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another;
    // they're in the commit history if you want to look (or I can go find them).
    let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time?
    attrs
        .iter()
        .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty())
}
<commit_msg>All five `has_repr_attr` agree + are correct<commit_after>use clippy_utils::{
    diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then},
    source::{indent_of, snippet},
};
use rustc_ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::{HirId, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::{self as ty_mod, Const, ReprFlags};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
    ///
    /// ### Why is this bad?
    /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
    ///
    /// ### Example
    /// ```rust
    /// struct RarelyUseful {
    ///     some_field: usize,
    ///     last: [SomeType; 0],
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust
    /// #[repr(C)]
    /// struct MoreOftenUseful {
    ///     some_field: usize,
    ///     last: [SomeType; 0],
    /// }
    /// ```
    pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
    nursery,
    "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
}
declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR]);

impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
        dbg!(item.ident);
        if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item) {
            eprintln!("consider yourself linted 😎");
            // span_lint_and_help(
            //     cx,
            //     TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR,
            //     item.span,
            //     "trailing zero-sized array in a struct which is not marked with a `repr`
            //     attribute",
            //     None,
            //     "consider annotating the struct definition with `#[repr(C)]` or another
            //     `repr` attribute",
            // );
        }
    }
}

fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
    // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer
    // doesn't work when it's an `if_chain`.

    // First check if last field is an array
    if let ItemKind::Struct(data, _) = &item.kind {
        if let Some(last_field) = data.fields().last() {
            if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind {
                // Then check if that that array zero-sized
                let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
                let length = Const::from_anon_const(cx.tcx, length_ldid);
                let length = length.try_eval_usize(cx.tcx, cx.param_env);
                length == Some(0)
            } else {
                false
            }
        } else {
            false
        }
    } else {
        false
    }
}

fn has_repr_attr(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
    // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed
    // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another;
    // they're in the commit history if you want to look (or I can go find them).

    let attrs1 = cx.tcx.hir().attrs(item.hir_id());
    let attrs2 = cx.tcx.get_attrs(item.def_id.to_def_id());

    let res11 = {
        let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time?
        attrs1
            .iter()
            .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty())
    };
    let res12 = { attrs1.iter().any(|attr| attr.has_name(sym::repr)) };

    let res21 = {
        let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time?
        attrs2
            .iter()
            .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty())
    };
    let res22 = { attrs2.iter().any(|attr| attr.has_name(sym::repr)) };

    let res_adt = {
        let ty = cx.tcx.type_of(item.def_id.to_def_id());
        if let ty_mod::Adt(adt, _) = ty.kind() {
            if adt.is_struct() {
                let repr = adt.repr;
                let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR;
                repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr)
            } else {
                false
            }
        } else {
            false
        }
    };

    let all_same = (res11 && res12 && res21 && res22 && res_adt) || (!res11 && !res12 && !res21 && !res22 && !res_adt);

    dbg!((
        (res11, res12, res21, res22, res_adt),
        all_same,
    ));

    res12
}
<|endoftext|>


<commit_before>mod java_code;
mod rust_code;

use std::fmt;

use log::{debug, trace};
use petgraph::Direction;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{parse_quote, spanned::Spanned, Type};

use crate::{
    ast::{change_span, fn_arg_type, normalize_ty_lifetimes, RustType},
    error::{DiagnosticError, Result},
    typemap::{
        make_unique_rust_typename, ForeignMethodSignature, ForeignTypeInfo, FROM_VAR_TEMPLATE,
        TO_VAR_TEMPLATE,
    },
    ForeignEnumInfo, ForeignInterface, ForeignerClassInfo, ForeignerMethod, JavaConfig,
    LanguageGenerator, MethodVariant, TypeMap,
};

struct JavaForeignTypeInfo {
    pub base: ForeignTypeInfo,
    pub java_transition_type: Option<String>,
    java_converter: String,
}

impl AsRef<ForeignTypeInfo> for JavaForeignTypeInfo {
    fn as_ref(&self) -> &ForeignTypeInfo {
        &self.base
    }
}

impl JavaForeignTypeInfo {
    fn java_need_conversation(&self) -> bool {
        !self.java_converter.is_empty()
    }
    fn java_convert<NameArg: Fn() -> (String, String)>(&self, name_arg: NameArg) -> Option<String> {
        if !self.java_converter.is_empty() {
            let (from_name, to_name) = name_arg();
            Some(
                self.java_converter
                    .replace(TO_VAR_TEMPLATE, &to_name)
                    .replace(FROM_VAR_TEMPLATE, &from_name),
            )
        } else {
            None
        }
    }
}

impl From<ForeignTypeInfo> for JavaForeignTypeInfo {
    fn from(x: ForeignTypeInfo) -> Self {
        JavaForeignTypeInfo {
            base: ForeignTypeInfo {
                name: x.name,
                correspoding_rust_type: x.correspoding_rust_type,
            },
            java_transition_type: None,
            java_converter: String::new(),
        }
    }
}

struct JniForeignMethodSignature {
    output: ForeignTypeInfo,
    input: Vec<JavaForeignTypeInfo>,
}

impl ForeignMethodSignature for JniForeignMethodSignature {
    type FI = JavaForeignTypeInfo;
    fn output(&self) -> &ForeignTypeInfo {
        &self.output
    }
    fn input(&self) -> &[JavaForeignTypeInfo] {
        &self.input[..]
    }
}

impl LanguageGenerator for JavaConfig {
    fn generate(
        &self,
        conv_map: &mut TypeMap,
        _: usize,
        class: &ForeignerClassInfo,
    ) -> Result<Vec<TokenStream>> {
        debug!(
            "generate: begin for {}, this_type_for_method {:?}",
            class.name, class.this_type_for_method
        );
        class
            .validate_class()
            .map_err(|err| DiagnosticError::new(class.span(), &err))?;
        if let Some(this_type_for_method) = class.this_type_for_method.as_ref() {
            let this_type: RustType = this_type_for_method.clone().into();
            let this_type = this_type.implements("SwigForeignClass");
            let jobject_name = "jobject";
            let jobject_ty = parse_type! { jobject };
            let my_jobj_ti = RustType::new(
                jobject_ty,
                make_unique_rust_typename(jobject_name, &this_type.normalized_name),
            );
            conv_map.cache_rust_to_foreign_conv(
                &this_type,
                ForeignTypeInfo {
                    correspoding_rust_type: my_jobj_ti,
                    name: class.name.to_string().into(),
                },
            );
        }

        let f_methods_sign = find_suitable_foreign_types_for_methods(conv_map, class)?;
        java_code::generate_java_code(
            &self.output_dir,
            &self.package_name,
            class,
            &f_methods_sign,
            self.use_null_annotation.as_ref().map(|x| &**x),
        )
        .map_err(|err| DiagnosticError::new(class.span(), &err))?;
        debug!("generate: java code done");
        let ast_items =
            rust_code::generate_rust_code(conv_map, &self.package_name, class, &f_methods_sign)?;

        Ok(ast_items)
    }

    fn generate_enum(
        &self,
        conv_map: &mut TypeMap,
        pointer_target_width: usize,
        enum_info: &ForeignEnumInfo,
    ) -> Result<Vec<TokenStream>> {
        if (enum_info.items.len() as u64) >= (i32::max_value() as u64) {
            return Err(DiagnosticError::new(
                enum_info.span(),
                "Too many items in enum",
            ));
        }

        java_code::generate_java_code_for_enum(&self.output_dir, &self.package_name, enum_info)
            .map_err(|err| DiagnosticError::new(enum_info.span(), &err))?;

        rust_code::generate_rust_code_for_enum(
            &self.package_name,
            conv_map,
            pointer_target_width,
            enum_info,
        )
    }

    fn generate_interface(
        &self,
        conv_map: &mut TypeMap,
        pointer_target_width: usize,
        interface: &ForeignInterface,
    ) -> Result<Vec<TokenStream>> {
        let f_methods = find_suitable_ftypes_for_interace_methods(conv_map, interface)?;
        java_code::generate_java_code_for_interface(
            &self.output_dir,
            &self.package_name,
            interface,
            &f_methods,
            self.use_null_annotation.as_ref().map(|x| &**x),
        )
        .map_err(|err| DiagnosticError::new(interface.span(), err))?;
        let items = rust_code::generate_interface(
            &self.package_name,
            conv_map,
            pointer_target_width,
            interface,
            &f_methods,
        )?;
        let jobject_name = "jobject";
        let jobject_ty = parse_type! { jobject };
        let my_jobj_ti = RustType::new(
            jobject_ty,
            make_unique_rust_typename(jobject_name, &interface.name.to_string()),
        );
        conv_map.add_foreign(my_jobj_ti, interface.name.to_string().into());
        Ok(items)
    }
}

fn method_name(method: &ForeignerMethod, f_method: &JniForeignMethodSignature) -> String {
    let need_conv = f_method.input.iter().any(|v| v.java_need_conversation());
    match method.variant {
        MethodVariant::StaticMethod if !need_conv => method.short_name().as_str().to_string(),
        MethodVariant::Method(_) | MethodVariant::StaticMethod => {
            format!("do_{}", method.short_name())
        }
        MethodVariant::Constructor => "init".into(),
    }
}

fn find_suitable_ftypes_for_interace_methods(
    conv_map: &mut TypeMap,
    interace: &ForeignInterface,
) -> Result<Vec<JniForeignMethodSignature>> {
    let void_sym = "void";
    let dummy_ty = parse_type! { () };
    let mut f_methods = vec![];

    for method in &interace.items {
        let mut input = Vec::<JavaForeignTypeInfo>::with_capacity(method.fn_decl.inputs.len() - 1);
        for arg in method.fn_decl.inputs.iter().skip(1) {
            let f_arg_type = conv_map
                .map_through_conversation_to_foreign(
                    fn_arg_type(arg),
                    Direction::Outgoing,
                    fn_arg_type(arg).span(),
                )
                .ok_or_else(|| {
                    DiagnosticError::new(
                        fn_arg_type(arg).span(),
                        format!(
                            "Do not know conversation to foreign \
                             from such rust type '{}'",
                            normalize_ty_lifetimes(fn_arg_type(arg))
                        ),
                    )
                })?;
            input.push(f_arg_type.into());
        }
        let output = match method.fn_decl.output {
            syn::ReturnType::Default => ForeignTypeInfo {
                name: void_sym.into(),
                correspoding_rust_type: {
                    let mut ty: Type = dummy_ty.clone();
                    change_span(&mut ty, method.fn_decl.span());
                    ty.into()
                },
            },
            _ => unimplemented!(),
        };
        f_methods.push(JniForeignMethodSignature { output, input });
    }
    Ok(f_methods)
}

fn find_suitable_foreign_types_for_methods(
    conv_map: &mut TypeMap,
    class: &ForeignerClassInfo,
) -> Result<Vec<JniForeignMethodSignature>> {
    let mut ret = Vec::<JniForeignMethodSignature>::with_capacity(class.methods.len());
    let empty_symbol = "";
    let dummy_ty = parse_type! { () };

    for method in &class.methods {
        //skip self argument
        let skip_n = match method.variant {
            MethodVariant::Method(_) => 1,
            _ => 0,
        };
        assert!(method.fn_decl.inputs.len() >= skip_n);
        let mut input =
            Vec::<JavaForeignTypeInfo>::with_capacity(method.fn_decl.inputs.len() - skip_n);
        for arg in method.fn_decl.inputs.iter().skip(skip_n) {
            if let Some(converter) = special_type(conv_map, fn_arg_type(arg))? {
                input.push(converter);
                continue;
            }

            let f_arg_type = conv_map
                .map_through_conversation_to_foreign(
                    fn_arg_type(arg),
                    Direction::Incoming,
                    fn_arg_type(arg).span(),
                )
                .ok_or_else(|| {
                    DiagnosticError::new(
                        fn_arg_type(arg).span(),
                        format!(
                            "Do not know conversation from foreign \
                             to such rust type '{}'",
                            normalize_ty_lifetimes(fn_arg_type(arg))
                        ),
                    )
                })?;
            input.push(f_arg_type.into());
        }
        let output = match method.variant {
            MethodVariant::Constructor => ForeignTypeInfo {
                name: empty_symbol.into(),
                correspoding_rust_type: dummy_ty.clone().into(),
            },
            _ => match method.fn_decl.output {
                syn::ReturnType::Default => ForeignTypeInfo {
                    name: "void".into(),
                    correspoding_rust_type: {
                        let mut ty: Type = dummy_ty.clone();
                        change_span(&mut ty, method.fn_decl.output.span());
                        ty.into()
                    },
                },
                syn::ReturnType::Type(_, ref rt) => conv_map
                    .map_through_conversation_to_foreign(&*rt, Direction::Outgoing, rt.span())
                    .ok_or_else(|| {
                        DiagnosticError::new(
                            rt.span(),
                            format!(
                                "Do not know conversation from \
                                 such rust type '{}' to foreign",
                                normalize_ty_lifetimes(&*rt)
                            ),
                        )
                    })?,
            },
        };
        ret.push(JniForeignMethodSignature { output, input });
    }
    Ok(ret)
}

fn fmt_write_err_map(err: fmt::Error) -> String {
    format!("fmt write error: {}", err)
}

fn java_class_full_name(package_name: &str, class_name: &str) -> String {
    let mut ret: String = package_name.into();
    ret.push('.');
    ret.push_str(class_name);
    ret
}

fn java_class_name_to_jni(full_name: &str) -> String {
    full_name.replace(".", "/")
}

fn calc_converter_for_foreign_class_arg(
    foreigner_class: &ForeignerClassInfo,
    arg_ty: &Type,
) -> JavaForeignTypeInfo {
    let this_ty = foreigner_class.this_type_for_method.as_ref().unwrap();
    let this_ty: RustType = this_ty.clone().into();

    let java_converter = if this_ty.normalized_name == normalize_ty_lifetimes(arg_ty) {
        r#"
        long {to_var} = {from_var}.mNativeObj;
        {from_var}.mNativeObj = 0;
"#
        .to_string()
    } else if let syn::Type::Reference(syn::TypeReference { ref elem, .. }) = arg_ty {
        assert_eq!(normalize_ty_lifetimes(elem), this_ty.normalized_name);
        r#"
        long {to_var} = {from_var}.mNativeObj;
"#
        .to_string()
    } else {
        unreachable!();
    };
    let jlong_ti: RustType = parse_type! { jlong }.into();
    JavaForeignTypeInfo {
        base: ForeignTypeInfo {
            name: foreigner_class.name.to_string().into(),
            correspoding_rust_type: jlong_ti,
        },
        java_transition_type: Some("long".into()),
        java_converter,
    }
}

fn calc_converter_for_enum(foreign_enum: &ForeignEnumInfo) -> JavaForeignTypeInfo {
    let jint_ti: RustType = parse_type! { jint }.into();
    let java_converter: String = r#"
        int {to_var} = {from_var}.getValue();
"#
    .into();
    JavaForeignTypeInfo {
        base: ForeignTypeInfo {
            name: foreign_enum.name.to_string().into(),
            correspoding_rust_type: jint_ti,
        },
        java_transition_type: Some("int".into()),
        java_converter,
    }
}

fn special_type(conv_map: &TypeMap, arg_ty: &Type) -> Result<Option<JavaForeignTypeInfo>> {
    let foreign_class_trait = "SwigForeignClass";

    trace!(
        "Check is arg.ty({:?}) implements foreign_class_trait",
        arg_ty
    );

    if let Some(foreign_class_this_ty) = conv_map.is_ty_implements(arg_ty, foreign_class_trait) {
        let foreigner_class = conv_map
            .find_foreigner_class_with_such_this_type(&foreign_class_this_ty.ty)
            .ok_or_else(|| {
                DiagnosticError::new(
                    arg_ty.span(),
                    format!("Can not find foreigner_class for '{:?}'", arg_ty),
                )
            })?;
        let converter = calc_converter_for_foreign_class_arg(foreigner_class, arg_ty);
        return Ok(Some(converter));
    }
    trace!("Check is arg.ty({:?}) implements exported enum", arg_ty);
    if let Some(foreign_enum) = conv_map.is_this_exported_enum(arg_ty) {
        let converter = calc_converter_for_enum(foreign_enum);
        return Ok(Some(converter));
    }

    trace!("Check is arg.ty({:?}) self type of foreign class", arg_ty);
    if let Some(foreign_class) = conv_map.find_foreigner_class_with_such_self_type(arg_ty, true) {
        let jlong_ti: RustType = parse_type! { jlong }.into();
        let converter = JavaForeignTypeInfo {
            base: ForeignTypeInfo {
                name: foreign_class.name.to_string().into(),
                correspoding_rust_type: jlong_ti,
            },
            java_transition_type: Some("long".into()),
            java_converter: "        long {to_var} = {from_var}.mNativeObj;".to_string(),
        };
        return Ok(Some(converter));
    }

    trace!("Oridinary type {:?}", arg_ty);
    Ok(None)
}
<commit_msg>java/jni refactoring: use SmolStr for transition type name<commit_after>mod java_code;
mod rust_code;

use std::fmt;

use log::{debug, trace};
use petgraph::Direction;
use proc_macro2::TokenStream;
use quote::quote;
use smol_str::SmolStr;
use syn::{parse_quote, spanned::Spanned, Type};

use crate::{
    ast::{change_span, fn_arg_type, normalize_ty_lifetimes, RustType},
    error::{DiagnosticError, Result},
    typemap::{
        make_unique_rust_typename, ForeignMethodSignature, ForeignTypeInfo, FROM_VAR_TEMPLATE,
        TO_VAR_TEMPLATE,
    },
    ForeignEnumInfo, ForeignInterface, ForeignerClassInfo, ForeignerMethod, JavaConfig,
    LanguageGenerator, MethodVariant, TypeMap,
};

struct JavaForeignTypeInfo {
    pub base: ForeignTypeInfo,
    pub java_transition_type: Option<SmolStr>,
    java_converter: String,
}

impl AsRef<ForeignTypeInfo> for JavaForeignTypeInfo {
    fn as_ref(&self) -> &ForeignTypeInfo {
        &self.base
    }
}

impl JavaForeignTypeInfo {
    fn java_need_conversation(&self) -> bool {
        !self.java_converter.is_empty()
    }
    fn java_convert<NameArg: Fn() -> (String, String)>(&self, name_arg: NameArg) -> Option<String> {
        if !self.java_converter.is_empty() {
            let (from_name, to_name) = name_arg();
            Some(
                self.java_converter
                    .replace(TO_VAR_TEMPLATE, &to_name)
                    .replace(FROM_VAR_TEMPLATE, &from_name),
            )
        } else {
            None
        }
    }
}

impl From<ForeignTypeInfo> for JavaForeignTypeInfo {
    fn from(x: ForeignTypeInfo) -> Self {
        JavaForeignTypeInfo {
            base: ForeignTypeInfo {
                name: x.name,
                correspoding_rust_type: x.correspoding_rust_type,
            },
            java_transition_type: None,
            java_converter: String::new(),
        }
    }
}

struct JniForeignMethodSignature {
    output: ForeignTypeInfo,
    input: Vec<JavaForeignTypeInfo>,
}

impl ForeignMethodSignature for JniForeignMethodSignature {
    type FI = JavaForeignTypeInfo;
    fn output(&self) -> &ForeignTypeInfo {
        &self.output
    }
    fn input(&self) -> &[JavaForeignTypeInfo] {
        &self.input[..]
    }
}

impl LanguageGenerator for JavaConfig {
    fn generate(
        &self,
        conv_map: &mut TypeMap,
        _: usize,
        class: &ForeignerClassInfo,
    ) -> Result<Vec<TokenStream>> {
        debug!(
            "generate: begin for {}, this_type_for_method {:?}",
            class.name, class.this_type_for_method
        );
        class
            .validate_class()
            .map_err(|err| DiagnosticError::new(class.span(), &err))?;
        if let Some(this_type_for_method) = class.this_type_for_method.as_ref() {
            let this_type: RustType = this_type_for_method.clone().into();
            let this_type = this_type.implements("SwigForeignClass");
            let jobject_name = "jobject";
            let jobject_ty = parse_type! { jobject };
            let my_jobj_ti = RustType::new(
                jobject_ty,
                make_unique_rust_typename(jobject_name, &this_type.normalized_name),
            );
            conv_map.cache_rust_to_foreign_conv(
                &this_type,
                ForeignTypeInfo {
                    correspoding_rust_type: my_jobj_ti,
                    name: class.name.to_string().into(),
                },
            );
        }

        let f_methods_sign = find_suitable_foreign_types_for_methods(conv_map, class)?;
        java_code::generate_java_code(
            &self.output_dir,
            &self.package_name,
            class,
            &f_methods_sign,
            self.use_null_annotation.as_ref().map(|x| &**x),
        )
        .map_err(|err| DiagnosticError::new(class.span(), &err))?;
        debug!("generate: java code done");
        let ast_items =
            rust_code::generate_rust_code(conv_map, &self.package_name, class, &f_methods_sign)?;

        Ok(ast_items)
    }

    fn generate_enum(
        &self,
        conv_map: &mut TypeMap,
        pointer_target_width: usize,
        enum_info: &ForeignEnumInfo,
    ) -> Result<Vec<TokenStream>> {
        if (enum_info.items.len() as u64) >= (i32::max_value() as u64) {
            return Err(DiagnosticError::new(
                enum_info.span(),
                "Too many items in enum",
            ));
        }

        java_code::generate_java_code_for_enum(&self.output_dir, &self.package_name, enum_info)
            .map_err(|err| DiagnosticError::new(enum_info.span(), &err))?;

        rust_code::generate_rust_code_for_enum(
            &self.package_name,
            conv_map,
            pointer_target_width,
            enum_info,
        )
    }

    fn generate_interface(
        &self,
        conv_map: &mut TypeMap,
        pointer_target_width: usize,
        interface: &ForeignInterface,
    ) -> Result<Vec<TokenStream>> {
        let f_methods = find_suitable_ftypes_for_interace_methods(conv_map, interface)?;
        java_code::generate_java_code_for_interface(
            &self.output_dir,
            &self.package_name,
            interface,
            &f_methods,
            self.use_null_annotation.as_ref().map(|x| &**x),
        )
        .map_err(|err| DiagnosticError::new(interface.span(), err))?;
        let items = rust_code::generate_interface(
            &self.package_name,
            conv_map,
            pointer_target_width,
            interface,
            &f_methods,
        )?;
        let jobject_name = "jobject";
        let jobject_ty = parse_type! { jobject };
        let my_jobj_ti = RustType::new(
            jobject_ty,
            make_unique_rust_typename(jobject_name, &interface.name.to_string()),
        );
        conv_map.add_foreign(my_jobj_ti, interface.name.to_string().into());
        Ok(items)
    }
}

fn method_name(method: &ForeignerMethod, f_method: &JniForeignMethodSignature) -> String {
    let need_conv = f_method.input.iter().any(|v| v.java_need_conversation());
    match method.variant {
        MethodVariant::StaticMethod if !need_conv => method.short_name().as_str().to_string(),
        MethodVariant::Method(_) | MethodVariant::StaticMethod => {
            format!("do_{}", method.short_name())
        }
        MethodVariant::Constructor => "init".into(),
    }
}

fn find_suitable_ftypes_for_interace_methods(
    conv_map: &mut TypeMap,
    interace: &ForeignInterface,
) -> Result<Vec<JniForeignMethodSignature>> {
    let void_sym = "void";
    let dummy_ty = parse_type! { () };
    let mut f_methods = vec![];

    for method in &interace.items {
        let mut input = Vec::<JavaForeignTypeInfo>::with_capacity(method.fn_decl.inputs.len() - 1);
        for arg in method.fn_decl.inputs.iter().skip(1) {
            let f_arg_type = conv_map
                .map_through_conversation_to_foreign(
                    fn_arg_type(arg),
                    Direction::Outgoing,
                    fn_arg_type(arg).span(),
                )
                .ok_or_else(|| {
                    DiagnosticError::new(
                        fn_arg_type(arg).span(),
                        format!(
                            "Do not know conversation to foreign \
                             from such rust type '{}'",
                            normalize_ty_lifetimes(fn_arg_type(arg))
                        ),
                    )
                })?;
            input.push(f_arg_type.into());
        }
        let output = match method.fn_decl.output {
            syn::ReturnType::Default => ForeignTypeInfo {
                name: void_sym.into(),
                correspoding_rust_type: {
                    let mut ty: Type = dummy_ty.clone();
                    change_span(&mut ty, method.fn_decl.span());
                    ty.into()
                },
            },
            _ => unimplemented!(),
        };
        f_methods.push(JniForeignMethodSignature { output, input });
    }
    Ok(f_methods)
}

fn find_suitable_foreign_types_for_methods(
    conv_map: &mut TypeMap,
    class: &ForeignerClassInfo,
) -> Result<Vec<JniForeignMethodSignature>> {
    let mut ret = Vec::<JniForeignMethodSignature>::with_capacity(class.methods.len());
    let empty_symbol = "";
    let dummy_ty = parse_type! { () };

    for method in &class.methods {
        //skip self argument
        let skip_n = match method.variant {
            MethodVariant::Method(_) => 1,
            _ => 0,
        };
        assert!(method.fn_decl.inputs.len() >= skip_n);
        let mut input =
            Vec::<JavaForeignTypeInfo>::with_capacity(method.fn_decl.inputs.len() - skip_n);
        for arg in method.fn_decl.inputs.iter().skip(skip_n) {
            if let Some(converter) = special_type(conv_map, fn_arg_type(arg))? {
                input.push(converter);
                continue;
            }

            let f_arg_type = conv_map
                .map_through_conversation_to_foreign(
                    fn_arg_type(arg),
                    Direction::Incoming,
                    fn_arg_type(arg).span(),
                )
                .ok_or_else(|| {
                    DiagnosticError::new(
                        fn_arg_type(arg).span(),
                        format!(
                            "Do not know conversation from foreign \
                             to such rust type '{}'",
                            normalize_ty_lifetimes(fn_arg_type(arg))
                        ),
                    )
                })?;
            input.push(f_arg_type.into());
        }
        let output = match method.variant {
            MethodVariant::Constructor => ForeignTypeInfo {
                name: empty_symbol.into(),
                correspoding_rust_type: dummy_ty.clone().into(),
            },
            _ => match method.fn_decl.output {
                syn::ReturnType::Default => ForeignTypeInfo {
                    name: "void".into(),
                    correspoding_rust_type: {
                        let mut ty: Type = dummy_ty.clone();
                        change_span(&mut ty, method.fn_decl.output.span());
                        ty.into()
                    },
                },
                syn::ReturnType::Type(_, ref rt) => conv_map
                    .map_through_conversation_to_foreign(&*rt, Direction::Outgoing, rt.span())
                    .ok_or_else(|| {
                        DiagnosticError::new(
                            rt.span(),
                            format!(
                                "Do not know conversation from \
                                 such rust type '{}' to foreign",
                                normalize_ty_lifetimes(&*rt)
                            ),
                        )
                    })?,
            },
        };
        ret.push(JniForeignMethodSignature { output, input });
    }
    Ok(ret)
}

fn fmt_write_err_map(err: fmt::Error) -> String {
    format!("fmt write error: {}", err)
}

fn java_class_full_name(package_name: &str, class_name: &str) -> String {
    let mut ret: String = package_name.into();
    ret.push('.');
    ret.push_str(class_name);
    ret
}

fn java_class_name_to_jni(full_name: &str) -> String {
    full_name.replace(".", "/")
}

fn calc_converter_for_foreign_class_arg(
    foreigner_class: &ForeignerClassInfo,
    arg_ty: &Type,
) -> JavaForeignTypeInfo {
    let this_ty = foreigner_class.this_type_for_method.as_ref().unwrap();
    let this_ty: RustType = this_ty.clone().into();

    let java_converter = if this_ty.normalized_name == normalize_ty_lifetimes(arg_ty) {
        r#"
        long {to_var} = {from_var}.mNativeObj;
        {from_var}.mNativeObj = 0;
"#
        .to_string()
    } else if let syn::Type::Reference(syn::TypeReference { ref elem, .. }) = arg_ty {
        assert_eq!(normalize_ty_lifetimes(elem), this_ty.normalized_name);
        r#"
        long {to_var} = {from_var}.mNativeObj;
"#
        .to_string()
    } else {
        unreachable!();
    };
    let jlong_ti: RustType = parse_type! { jlong }.into();
    JavaForeignTypeInfo {
        base: ForeignTypeInfo {
            name: foreigner_class.name.to_string().into(),
            correspoding_rust_type: jlong_ti,
        },
        java_transition_type: Some("long".into()),
        java_converter,
    }
}

fn calc_converter_for_enum(foreign_enum: &ForeignEnumInfo) -> JavaForeignTypeInfo {
    let jint_ti: RustType = parse_type! { jint }.into();
    let java_converter: String = r#"
        int {to_var} = {from_var}.getValue();
"#
    .into();
    JavaForeignTypeInfo {
        base: ForeignTypeInfo {
            name: foreign_enum.name.to_string().into(),
            correspoding_rust_type: jint_ti,
        },
        java_transition_type: Some("int".into()),
        java_converter,
    }
}

fn special_type(conv_map: &TypeMap, arg_ty: &Type) -> Result<Option<JavaForeignTypeInfo>> {
    let foreign_class_trait = "SwigForeignClass";

    trace!(
        "Check is arg.ty({:?}) implements foreign_class_trait",
        arg_ty
    );

    if let Some(foreign_class_this_ty) = conv_map.is_ty_implements(arg_ty, foreign_class_trait) {
        let foreigner_class = conv_map
            .find_foreigner_class_with_such_this_type(&foreign_class_this_ty.ty)
            .ok_or_else(|| {
                DiagnosticError::new(
                    arg_ty.span(),
                    format!("Can not find foreigner_class for '{:?}'", arg_ty),
                )
            })?;
        let converter = calc_converter_for_foreign_class_arg(foreigner_class, arg_ty);
        return Ok(Some(converter));
    }
    trace!("Check is arg.ty({:?}) implements exported enum", arg_ty);
    if let Some(foreign_enum) = conv_map.is_this_exported_enum(arg_ty) {
        let converter = calc_converter_for_enum(foreign_enum);
        return Ok(Some(converter));
    }

    trace!("Check is arg.ty({:?}) self type of foreign class", arg_ty);
    if let Some(foreign_class) = conv_map.find_foreigner_class_with_such_self_type(arg_ty, true) {
        let jlong_ti: RustType = parse_type! { jlong }.into();
        let converter = JavaForeignTypeInfo {
            base: ForeignTypeInfo {
                name: foreign_class.name.to_string().into(),
                correspoding_rust_type: jlong_ti,
            },
            java_transition_type: Some("long".into()),
            java_converter: "        long {to_var} = {from_var}.mNativeObj;".to_string(),
        };
        return Ok(Some(converter));
    }

    trace!("Oridinary type {:?}", arg_ty);
    Ok(None)
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use BlockNumber;
use crypto::{Signature, Public, pubkey_to_address, SIGNATURE_BYTES_LEN, HASH_BYTES_LEN, PUBKEY_BYTES_LEN};
use libproto::blockchain::{Transaction as ProtoTransaction, UnverifiedTransaction as ProtoUnverifiedTransaction, SignedTransaction as ProtoSignedTransaction, Crypto as ProtoCrypto};
use rlp::*;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use util::{H256, Address, U256, Bytes, HeapSizeOf, H520, H512};

// pub const STORE_ADDRESS: H160 =  H160( [0xff; 20] );
pub const STORE_ADDRESS: &str = "ffffffffffffffffffffffffffffffffffffffff";

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    ParseError,
    InvalidHash,
    InvalidSignature,
    InvalidPubKey,
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// Transaction action type.
pub enum Action {
    /// Just store the data.
    Store,
    /// Create creates new contract.
    Create,
    /// Calls contract at given address.
    /// In the case of a transfer, this is the receiver's address.'
    Call(Address),
}

impl Default for Action {
    fn default() -> Action {
        Action::Create
    }
}

impl Decodable for Action {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        if rlp.is_empty() {
            Ok(Action::Create)
        } else {
            let store_addr: Address = STORE_ADDRESS.into();
            let addr: Address = rlp.as_val()?;
            if addr == store_addr { Ok(Action::Store) } else { Ok(Action::Call(addr)) }
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// crypto type.
pub enum CryptoType {
    SECP,
    SM2,
}

impl Default for CryptoType {
    fn default() -> CryptoType {
        CryptoType::SECP
    }
}

impl Decodable for CryptoType {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        match rlp.as_val::<u8>()? {
            0 => Ok(CryptoType::SECP),
            1 => Ok(CryptoType::SM2),
            _ => Err(DecoderError::Custom("Unknown Type.")),
        }
    }
}

impl Encodable for CryptoType {
    fn rlp_append(&self, s: &mut RlpStream) {
        match *self {
            CryptoType::SECP => s.append(&(0 as u8)),
            CryptoType::SM2 => s.append(&(1 as u8)),
        };
    }
}

impl From<ProtoCrypto> for CryptoType {
    fn from(c: ProtoCrypto) -> CryptoType {
        match c {
            ProtoCrypto::SECP => CryptoType::SECP,
            ProtoCrypto::SM2 => CryptoType::SM2,
        }
    }
}

/// A set of information describing an externally-originating message call
/// or contract creation operation.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Transaction {
    /// Nonce.
    pub nonce: U256,
    /// Gas price.
    pub gas_price: U256,
    /// Gas paid up front for transaction execution.
    pub gas: U256,
    /// Action, can be either call or contract create.
    pub action: Action,
    /// Transfered value.
    pub value: U256,
    /// Transaction data.
    pub data: Bytes,
    /// valid before this block number
    pub block_limit: BlockNumber,
}

impl HeapSizeOf for Transaction {
    fn heap_size_of_children(&self) -> usize {
        self.data.heap_size_of_children()
    }
}

impl Decodable for Transaction {
    fn decode(d: &UntrustedRlp) -> Result<Self, DecoderError> {
        if d.item_count()? != 7 {
            return Err(DecoderError::RlpIncorrectListLen);
        }
        Ok(Transaction {
               nonce: d.val_at(0)?,
               gas_price: d.val_at(1)?,
               gas: d.val_at(2)?,
               action: d.val_at(3)?,
               value: d.val_at(4)?,
               data: d.val_at(5)?,
               block_limit: d.val_at(6)?,
           })
    }
}

impl Encodable for Transaction {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.rlp_append_unsigned_transaction(s)
    }
}

// TODO: refactor transaction in protobuf,
// now using the same type `ProtoTransaction`,
// it's not a good design.
impl Transaction {
    pub fn new(plain_transaction: &ProtoTransaction) -> Result<Self, Error> {
        // let nonce = plain_transaction.nonce.parse::<u32>().map_err(|_| Error::ParseError)?;
        Ok(Transaction {
               nonce: U256::from_str(plain_transaction.get_nonce()).map_err(|_| Error::ParseError)?,
               gas_price: U256::default(),
               gas: U256::from(u64::max_value()),
               action: {
                   let to = plain_transaction.get_to();
                   match to.is_empty() {
                       true => Action::Create,
                       false => match to {
                           STORE_ADDRESS => Action::Store,
                           _ => Action::Call(Address::from_str(to).map_err(|_| Error::ParseError)?),
                       },
                   }
               },
               value: U256::default(),
               data: plain_transaction.get_data().into(),
               block_limit: plain_transaction.get_valid_until_block(),
           })

    }

    pub fn nonce(&self) -> &U256 {
        &self.nonce
    }

    pub fn action(&self) -> &Action {
        &self.action
    }

    // Specify the sender; this won't survive the serialize/deserialize process, but can be cloned.
    pub fn fake_sign(self, from: Address) -> SignedTransaction {
        let signature = Signature::from_rsv(&H256::default(), &H256::default(), 0);
        SignedTransaction {
            transaction: UnverifiedTransaction {
                unsigned: self,
                signature: signature,
                hash: 0.into(),
                crypto_type: CryptoType::default(),
            },
            sender: from,
            public: Public::default(),
        }
    }

    /// Append object with a without signature into RLP stream
    pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) {
        let store_addr: Address = STORE_ADDRESS.into();
        s.begin_list(7);
        s.append(&self.nonce);
        s.append(&self.gas_price);
        s.append(&self.gas);
        match self.action {
            Action::Create => s.append_empty_data(),
            Action::Call(ref to) => s.append(to),
            Action::Store => s.append(&store_addr),
        };
        s.append(&self.value);
        s.append(&self.data);
        s.append(&self.block_limit);
    }

    /// get the protobuf transaction
    pub fn proto_transaction(&self) -> ProtoTransaction {
        let mut pt = ProtoTransaction::new();
        pt.set_nonce(self.nonce.to_hex());
        pt.set_valid_until_block(self.block_limit);
        pt.set_data(self.data.clone());
        match self.action {
            Action::Create => pt.clear_to(),
            Action::Call(ref to) => pt.set_to(to.hex()),
            Action::Store => pt.set_to(STORE_ADDRESS.into()),
        }
        pt
    }
}

/// Signed transaction information without verified signature.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnverifiedTransaction {
    /// Plain Transaction.
    unsigned: Transaction,
    /// The signature
    signature: Signature,
    /// The Crypto Type
    crypto_type: CryptoType,
    /// Hash of the transaction
    hash: H256,
}

impl Deref for UnverifiedTransaction {
    type Target = Transaction;

    fn deref(&self) -> &Self::Target {
        &self.unsigned
    }
}

impl DerefMut for UnverifiedTransaction {
    fn deref_mut(&mut self) -> &mut Transaction {
        &mut self.unsigned
    }
}

impl Decodable for UnverifiedTransaction {
    fn decode(d: &UntrustedRlp) -> Result<Self, DecoderError> {
        if d.item_count()? != 4 {
            return Err(DecoderError::RlpIncorrectListLen);
        }
        Ok(UnverifiedTransaction {
               unsigned: d.val_at(0)?,
               signature: d.val_at(1)?,
               crypto_type: d.val_at(2)?,
               hash: d.val_at(3)?,
           })
    }
}

impl Encodable for UnverifiedTransaction {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.rlp_append_sealed_transaction(s)
    }
}

impl UnverifiedTransaction {
    fn new(utx: &ProtoUnverifiedTransaction, hash: H256) -> Result<Self, Error> {

        if utx.get_signature().len() != SIGNATURE_BYTES_LEN {
            return Err(Error::InvalidSignature);
        }

        Ok(UnverifiedTransaction {
               unsigned: Transaction::new(utx.get_transaction())?,
               signature: Signature::from(H520::from(utx.get_signature())),
               crypto_type: CryptoType::from(utx.get_crypto()),
               hash: hash,
           })
    }

    /// Append object with a signature into RLP stream
    fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
        s.begin_list(4);
        s.append(&self.unsigned);
        s.append(&self.signature);
        s.append(&self.crypto_type);
        s.append(&self.hash);
    }

    ///	Reference to unsigned part of this transaction.
    pub fn as_unsigned(&self) -> &Transaction {
        &self.unsigned
    }

    pub fn hash(&self) -> H256 {
        self.hash
    }

    /// get protobuf unverified transaction
    pub fn proto_unverified(&self) -> ProtoUnverifiedTransaction {
        let mut untx = ProtoUnverifiedTransaction::new();
        let tx = self.unsigned.proto_transaction();

        untx.set_transaction(tx);
        untx.set_signature(self.signature.to_vec());

        match self.crypto_type {
            CryptoType::SECP => untx.set_crypto(ProtoCrypto::SECP),
            CryptoType::SM2 => untx.set_crypto(ProtoCrypto::SM2),
        }
        untx
    }
}

/// A `UnverifiedTransaction` with successfully recovered `sender`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SignedTransaction {
    transaction: UnverifiedTransaction,
    sender: Address,
    public: Public,
}

impl Decodable for SignedTransaction {
    fn decode(d: &UntrustedRlp) -> Result<Self, DecoderError> {
        if d.item_count()? != 2 {
            return Err(DecoderError::RlpIncorrectListLen);
        }
        let public = d.val_at(1)?;
        Ok(SignedTransaction {
               transaction: d.val_at(0)?,
               sender: pubkey_to_address(&public),
               public: public,
           })
    }
}

impl Encodable for SignedTransaction {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.rlp_append_signed_transaction(s)
    }
}

impl HeapSizeOf for SignedTransaction {
    fn heap_size_of_children(&self) -> usize {
        self.transaction.heap_size_of_children()
    }
}

impl Deref for SignedTransaction {
    type Target = UnverifiedTransaction;
    fn deref(&self) -> &Self::Target {
        &self.transaction
    }
}

impl DerefMut for SignedTransaction {
    fn deref_mut(&mut self) -> &mut UnverifiedTransaction {
        &mut self.transaction
    }
}

impl SignedTransaction {
    /// Try to verify transaction and recover sender.
    pub fn new(stx: &ProtoSignedTransaction) -> Result<Self, Error> {
        if stx.get_tx_hash().len() != HASH_BYTES_LEN {
            return Err(Error::InvalidHash);
        }

        if stx.get_signer().len() != PUBKEY_BYTES_LEN {
            return Err(Error::InvalidPubKey);
        }

        let tx_hash = H256::from(stx.get_tx_hash());
        let public = H512::from_slice(stx.get_signer());
        let sender = pubkey_to_address(&public);
        Ok(SignedTransaction {
               transaction: UnverifiedTransaction::new(stx.get_transaction_with_sig(), tx_hash)?,
               sender: sender,
               public: public,
           })
    }

    /// Returns transaction sender.
    pub fn sender(&self) -> &Address {
        &self.sender
    }

    /// Returns a public key of the sender.
    pub fn public_key(&self) -> &Public {
        &self.public
    }

    /// Append object with a signature into RLP stream
    fn rlp_append_signed_transaction(&self, s: &mut RlpStream) {
        s.begin_list(2);
        s.append(&self.transaction);
        //TODO: remove it
        s.append(&self.public);
    }

    ///get protobuf of signed transaction
    pub fn protobuf(&self) -> ProtoSignedTransaction {
        let mut stx = ProtoSignedTransaction::new();
        let utx = self.transaction.proto_unverified();
        stx.set_transaction_with_sig(utx);
        stx.set_tx_hash(self.hash().to_vec());
        stx.set_signer(self.public.to_vec());
        stx
    }
}
<commit_msg>Change transaction gas to u32::max. (#20)<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use BlockNumber;
use crypto::{Signature, Public, pubkey_to_address, SIGNATURE_BYTES_LEN, HASH_BYTES_LEN, PUBKEY_BYTES_LEN};
use libproto::blockchain::{Transaction as ProtoTransaction, UnverifiedTransaction as ProtoUnverifiedTransaction, SignedTransaction as ProtoSignedTransaction, Crypto as ProtoCrypto};
use rlp::*;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use util::{H256, Address, U256, Bytes, HeapSizeOf, H520, H512};

// pub const STORE_ADDRESS: H160 =  H160( [0xff; 20] );
pub const STORE_ADDRESS: &str = "ffffffffffffffffffffffffffffffffffffffff";

#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    ParseError,
    InvalidHash,
    InvalidSignature,
    InvalidPubKey,
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// Transaction action type.
pub enum Action {
    /// Just store the data.
    Store,
    /// Create creates new contract.
    Create,
    /// Calls contract at given address.
    /// In the case of a transfer, this is the receiver's address.'
    Call(Address),
}

impl Default for Action {
    fn default() -> Action {
        Action::Create
    }
}

impl Decodable for Action {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        if rlp.is_empty() {
            Ok(Action::Create)
        } else {
            let store_addr: Address = STORE_ADDRESS.into();
            let addr: Address = rlp.as_val()?;
            if addr == store_addr { Ok(Action::Store) } else { Ok(Action::Call(addr)) }
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// crypto type.
pub enum CryptoType {
    SECP,
    SM2,
}

impl Default for CryptoType {
    fn default() -> CryptoType {
        CryptoType::SECP
    }
}

impl Decodable for CryptoType {
    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
        match rlp.as_val::<u8>()? {
            0 => Ok(CryptoType::SECP),
            1 => Ok(CryptoType::SM2),
            _ => Err(DecoderError::Custom("Unknown Type.")),
        }
    }
}

impl Encodable for CryptoType {
    fn rlp_append(&self, s: &mut RlpStream) {
        match *self {
            CryptoType::SECP => s.append(&(0 as u8)),
            CryptoType::SM2 => s.append(&(1 as u8)),
        };
    }
}

impl From<ProtoCrypto> for CryptoType {
    fn from(c: ProtoCrypto) -> CryptoType {
        match c {
            ProtoCrypto::SECP => CryptoType::SECP,
            ProtoCrypto::SM2 => CryptoType::SM2,
        }
    }
}

/// A set of information describing an externally-originating message call
/// or contract creation operation.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Transaction {
    /// Nonce.
    pub nonce: U256,
    /// Gas price.
    pub gas_price: U256,
    /// Gas paid up front for transaction execution.
    pub gas: U256,
    /// Action, can be either call or contract create.
    pub action: Action,
    /// Transfered value.
    pub value: U256,
    /// Transaction data.
    pub data: Bytes,
    /// valid before this block number
    pub block_limit: BlockNumber,
}

impl HeapSizeOf for Transaction {
    fn heap_size_of_children(&self) -> usize {
        self.data.heap_size_of_children()
    }
}

impl Decodable for Transaction {
    fn decode(d: &UntrustedRlp) -> Result<Self, DecoderError> {
        if d.item_count()? != 7 {
            return Err(DecoderError::RlpIncorrectListLen);
        }
        Ok(Transaction {
               nonce: d.val_at(0)?,
               gas_price: d.val_at(1)?,
               gas: d.val_at(2)?,
               action: d.val_at(3)?,
               value: d.val_at(4)?,
               data: d.val_at(5)?,
               block_limit: d.val_at(6)?,
           })
    }
}

impl Encodable for Transaction {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.rlp_append_unsigned_transaction(s)
    }
}

// TODO: refactor transaction in protobuf,
// now using the same type `ProtoTransaction`,
// it's not a good design.
impl Transaction {
    pub fn new(plain_transaction: &ProtoTransaction) -> Result<Self, Error> {
        // let nonce = plain_transaction.nonce.parse::<u32>().map_err(|_| Error::ParseError)?;
        Ok(Transaction {
               nonce: U256::from_str(plain_transaction.get_nonce()).map_err(|_| Error::ParseError)?,
               gas_price: U256::default(),
               gas: U256::from(u32::max_value()),
               action: {
                   let to = plain_transaction.get_to();
                   match to.is_empty() {
                       true => Action::Create,
                       false => match to {
                           STORE_ADDRESS => Action::Store,
                           _ => Action::Call(Address::from_str(to).map_err(|_| Error::ParseError)?),
                       },
                   }
               },
               value: U256::default(),
               data: plain_transaction.get_data().into(),
               block_limit: plain_transaction.get_valid_until_block(),
           })

    }

    pub fn nonce(&self) -> &U256 {
        &self.nonce
    }

    pub fn action(&self) -> &Action {
        &self.action
    }

    // Specify the sender; this won't survive the serialize/deserialize process, but can be cloned.
    pub fn fake_sign(self, from: Address) -> SignedTransaction {
        let signature = Signature::from_rsv(&H256::default(), &H256::default(), 0);
        SignedTransaction {
            transaction: UnverifiedTransaction {
                unsigned: self,
                signature: signature,
                hash: 0.into(),
                crypto_type: CryptoType::default(),
            },
            sender: from,
            public: Public::default(),
        }
    }

    /// Append object with a without signature into RLP stream
    pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) {
        let store_addr: Address = STORE_ADDRESS.into();
        s.begin_list(7);
        s.append(&self.nonce);
        s.append(&self.gas_price);
        s.append(&self.gas);
        match self.action {
            Action::Create => s.append_empty_data(),
            Action::Call(ref to) => s.append(to),
            Action::Store => s.append(&store_addr),
        };
        s.append(&self.value);
        s.append(&self.data);
        s.append(&self.block_limit);
    }

    /// get the protobuf transaction
    pub fn proto_transaction(&self) -> ProtoTransaction {
        let mut pt = ProtoTransaction::new();
        pt.set_nonce(self.nonce.to_hex());
        pt.set_valid_until_block(self.block_limit);
        pt.set_data(self.data.clone());
        match self.action {
            Action::Create => pt.clear_to(),
            Action::Call(ref to) => pt.set_to(to.hex()),
            Action::Store => pt.set_to(STORE_ADDRESS.into()),
        }
        pt
    }
}

/// Signed transaction information without verified signature.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnverifiedTransaction {
    /// Plain Transaction.
    unsigned: Transaction,
    /// The signature
    signature: Signature,
    /// The Crypto Type
    crypto_type: CryptoType,
    /// Hash of the transaction
    hash: H256,
}

impl Deref for UnverifiedTransaction {
    type Target = Transaction;

    fn deref(&self) -> &Self::Target {
        &self.unsigned
    }
}

impl DerefMut for UnverifiedTransaction {
    fn deref_mut(&mut self) -> &mut Transaction {
        &mut self.unsigned
    }
}

impl Decodable for UnverifiedTransaction {
    fn decode(d: &UntrustedRlp) -> Result<Self, DecoderError> {
        if d.item_count()? != 4 {
            return Err(DecoderError::RlpIncorrectListLen);
        }
        Ok(UnverifiedTransaction {
               unsigned: d.val_at(0)?,
               signature: d.val_at(1)?,
               crypto_type: d.val_at(2)?,
               hash: d.val_at(3)?,
           })
    }
}

impl Encodable for UnverifiedTransaction {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.rlp_append_sealed_transaction(s)
    }
}

impl UnverifiedTransaction {
    fn new(utx: &ProtoUnverifiedTransaction, hash: H256) -> Result<Self, Error> {

        if utx.get_signature().len() != SIGNATURE_BYTES_LEN {
            return Err(Error::InvalidSignature);
        }

        Ok(UnverifiedTransaction {
               unsigned: Transaction::new(utx.get_transaction())?,
               signature: Signature::from(H520::from(utx.get_signature())),
               crypto_type: CryptoType::from(utx.get_crypto()),
               hash: hash,
           })
    }

    /// Append object with a signature into RLP stream
    fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
        s.begin_list(4);
        s.append(&self.unsigned);
        s.append(&self.signature);
        s.append(&self.crypto_type);
        s.append(&self.hash);
    }

    ///	Reference to unsigned part of this transaction.
    pub fn as_unsigned(&self) -> &Transaction {
        &self.unsigned
    }

    pub fn hash(&self) -> H256 {
        self.hash
    }

    /// get protobuf unverified transaction
    pub fn proto_unverified(&self) -> ProtoUnverifiedTransaction {
        let mut untx = ProtoUnverifiedTransaction::new();
        let tx = self.unsigned.proto_transaction();

        untx.set_transaction(tx);
        untx.set_signature(self.signature.to_vec());

        match self.crypto_type {
            CryptoType::SECP => untx.set_crypto(ProtoCrypto::SECP),
            CryptoType::SM2 => untx.set_crypto(ProtoCrypto::SM2),
        }
        untx
    }
}

/// A `UnverifiedTransaction` with successfully recovered `sender`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SignedTransaction {
    transaction: UnverifiedTransaction,
    sender: Address,
    public: Public,
}

impl Decodable for SignedTransaction {
    fn decode(d: &UntrustedRlp) -> Result<Self, DecoderError> {
        if d.item_count()? != 2 {
            return Err(DecoderError::RlpIncorrectListLen);
        }
        let public = d.val_at(1)?;
        Ok(SignedTransaction {
               transaction: d.val_at(0)?,
               sender: pubkey_to_address(&public),
               public: public,
           })
    }
}

impl Encodable for SignedTransaction {
    fn rlp_append(&self, s: &mut RlpStream) {
        self.rlp_append_signed_transaction(s)
    }
}

impl HeapSizeOf for SignedTransaction {
    fn heap_size_of_children(&self) -> usize {
        self.transaction.heap_size_of_children()
    }
}

impl Deref for SignedTransaction {
    type Target = UnverifiedTransaction;
    fn deref(&self) -> &Self::Target {
        &self.transaction
    }
}

impl DerefMut for SignedTransaction {
    fn deref_mut(&mut self) -> &mut UnverifiedTransaction {
        &mut self.transaction
    }
}

impl SignedTransaction {
    /// Try to verify transaction and recover sender.
    pub fn new(stx: &ProtoSignedTransaction) -> Result<Self, Error> {
        if stx.get_tx_hash().len() != HASH_BYTES_LEN {
            return Err(Error::InvalidHash);
        }

        if stx.get_signer().len() != PUBKEY_BYTES_LEN {
            return Err(Error::InvalidPubKey);
        }

        let tx_hash = H256::from(stx.get_tx_hash());
        let public = H512::from_slice(stx.get_signer());
        let sender = pubkey_to_address(&public);
        Ok(SignedTransaction {
               transaction: UnverifiedTransaction::new(stx.get_transaction_with_sig(), tx_hash)?,
               sender: sender,
               public: public,
           })
    }

    /// Returns transaction sender.
    pub fn sender(&self) -> &Address {
        &self.sender
    }

    /// Returns a public key of the sender.
    pub fn public_key(&self) -> &Public {
        &self.public
    }

    /// Append object with a signature into RLP stream
    fn rlp_append_signed_transaction(&self, s: &mut RlpStream) {
        s.begin_list(2);
        s.append(&self.transaction);
        //TODO: remove it
        s.append(&self.public);
    }

    ///get protobuf of signed transaction
    pub fn protobuf(&self) -> ProtoSignedTransaction {
        let mut stx = ProtoSignedTransaction::new();
        let utx = self.transaction.proto_unverified();
        stx.set_transaction_with_sig(utx);
        stx.set_tx_hash(self.hash().to_vec());
        stx.set_signer(self.public.to_vec());
        stx
    }
}
<|endoftext|>


<commit_before>// Helpers for handling cast expressions, used in both
// typeck and codegen.

use crate::ty::{self, Ty};

use rustc_ast as ast;
use rustc_macros::HashStable;

/// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IntTy {
    U(ast::UintTy),
    I,
    CEnum,
    Bool,
    Char,
}

// Valid types for the result of a non-coercion cast
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CastTy<'tcx> {
    /// Various types that are represented as ints and handled mostly
    /// in the same way, merged for easier matching.
    Int(IntTy),
    /// Floating-Point types
    Float,
    /// Function Pointers
    FnPtr,
    /// Raw pointers
    Ptr(ty::TypeAndMut<'tcx>),
}

/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum CastKind {
    CoercionCast,
    PtrPtrCast,
    PtrAddrCast,
    AddrPtrCast,
    NumericCast,
    EnumCast,
    PrimIntCast,
    U8CharCast,
    ArrayPtrCast,
    FnPtrPtrCast,
    FnPtrAddrCast,
}

impl<'tcx> CastTy<'tcx> {
    /// Returns `Some` for integral/pointer casts.
    /// casts like unsizing casts will return `None`
    pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> {
        match *t.kind() {
            ty::Bool => Some(CastTy::Int(IntTy::Bool)),
            ty::Char => Some(CastTy::Int(IntTy::Char)),
            ty::Int(_) => Some(CastTy::Int(IntTy::I)),
            ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)),
            ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float),
            ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))),
            ty::Float(_) => Some(CastTy::Float),
            ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
            ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
            ty::FnPtr(..) => Some(CastTy::FnPtr),
            _ => None,
        }
    }
}
<commit_msg>Edit rustc_middle::ty::cast docs<commit_after>// Helpers for handling cast expressions, used in both
// typeck and codegen.

use crate::ty::{self, Ty};

use rustc_ast as ast;
use rustc_macros::HashStable;

/// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IntTy {
    U(ast::UintTy),
    I,
    CEnum,
    Bool,
    Char,
}

// Valid types for the result of a non-coercion cast
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CastTy<'tcx> {
    /// Various types that are represented as ints and handled mostly
    /// in the same way, merged for easier matching.
    Int(IntTy),
    /// Floating-point types.
    Float,
    /// Function pointers.
    FnPtr,
    /// Raw pointers.
    Ptr(ty::TypeAndMut<'tcx>),
}

/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
/// (or librustc_typeck/check/cast.rs).
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum CastKind {
    CoercionCast,
    PtrPtrCast,
    PtrAddrCast,
    AddrPtrCast,
    NumericCast,
    EnumCast,
    PrimIntCast,
    U8CharCast,
    ArrayPtrCast,
    FnPtrPtrCast,
    FnPtrAddrCast,
}

impl<'tcx> CastTy<'tcx> {
    /// Returns `Some` for integral/pointer casts.
    /// Casts like unsizing casts will return `None`.
    pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> {
        match *t.kind() {
            ty::Bool => Some(CastTy::Int(IntTy::Bool)),
            ty::Char => Some(CastTy::Int(IntTy::Char)),
            ty::Int(_) => Some(CastTy::Int(IntTy::I)),
            ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)),
            ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float),
            ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))),
            ty::Float(_) => Some(CastTy::Float),
            ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
            ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
            ty::FnPtr(..) => Some(CastTy::FnPtr),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

pub mod info;
pub mod probe {
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Request {
        pub custom_server: String,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(rename_all = "snake_case")]
    pub enum Response {
        Updating,
        NoUpdate,
        TryAgain(i64),
    }
}

pub mod local_install {
    use serde::{Deserialize, Serialize};

    #[derive(Deserialize, Clone, Debug, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Request {
        pub file: std::path::PathBuf,
    }
}

pub mod remote_install {
    use serde::{Deserialize, Serialize};

    #[derive(Deserialize, Clone, Debug, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Request {
        pub url: String,
    }
}

pub mod state {
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Response {
        Park,
        EntryPoint,
        Poll,
        Probe,
        Validation,
        Download,
        Install,
        Reboot,
        DirectDownload,
        PrepareLocalInstall,
        Error,
    }
}

pub mod abort_download {
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Response {
        pub message: String,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Refused {
        pub error: String,
    }
}

pub mod log {
    use serde::{Deserialize, Serialize};
    use std::collections::HashMap;

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Level {
        Critical,
        Error,
        Warning,
        Info,
        Debug,
        Trace,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Log {
        entries: Vec<Entry>,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Entry {
        level: Level,
        message: String,
        time: String,
        data: HashMap<String, String>,
    }

    impl core::fmt::Display for Log {
        fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
            for entry in &self.entries {
                let level = match entry.level {
                    Level::Critical => "CRIT",
                    Level::Error => "ERRO",
                    Level::Warning => "WARN",
                    Level::Info => "INFO",
                    Level::Debug => "DEBG",
                    Level::Trace => "TRCE",
                };

                writeln!(
                    f,
                    "{timestamp} {level} {msg}",
                    timestamp = entry.time,
                    level = level,
                    msg = entry.message
                )?;
            }
            Ok(())
        }
    }
}
<commit_msg>updatehub-sdk: doc: Add doc for API<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

//! Contains all the structures of the request and response
//! from the agent.

/// Body of `info` response.
pub mod info;

/// Body of `probe` request and response.
pub mod probe {
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Request {
        pub custom_server: String,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(rename_all = "snake_case")]
    pub enum Response {
        Updating,
        NoUpdate,
        TryAgain(i64),
    }
}

/// Body of `local_install` request.
pub mod local_install {
    use serde::{Deserialize, Serialize};

    #[derive(Deserialize, Clone, Debug, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Request {
        pub file: std::path::PathBuf,
    }
}

/// Body of `remote_install` request.
pub mod remote_install {
    use serde::{Deserialize, Serialize};

    #[derive(Deserialize, Clone, Debug, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Request {
        pub url: String,
    }
}

/// Body of `state` response.
pub mod state {
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Response {
        Park,
        EntryPoint,
        Poll,
        Probe,
        Validation,
        Download,
        Install,
        Reboot,
        DirectDownload,
        PrepareLocalInstall,
        Error,
    }
}

/// Body of `abort_download` response.
///
/// # Successful case
///
/// On a successful request, the body of response is a struct
/// called `Response` with a successful message.
///
/// # Failed case
///
/// On a failed request, the body of response is a struct
/// called `Refused` with a error message.
pub mod abort_download {
    use serde::{Deserialize, Serialize};

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Response {
        pub message: String,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Refused {
        pub error: String,
    }
}

/// Body of `log` response.
pub mod log {
    use serde::{Deserialize, Serialize};
    use std::collections::HashMap;

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Level {
        Critical,
        Error,
        Warning,
        Info,
        Debug,
        Trace,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Log {
        entries: Vec<Entry>,
    }

    #[derive(Clone, Debug, Deserialize, Serialize)]
    #[serde(deny_unknown_fields)]
    pub struct Entry {
        level: Level,
        message: String,
        time: String,
        data: HashMap<String, String>,
    }

    impl core::fmt::Display for Log {
        fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
            for entry in &self.entries {
                let level = match entry.level {
                    Level::Critical => "CRIT",
                    Level::Error => "ERRO",
                    Level::Warning => "WARN",
                    Level::Info => "INFO",
                    Level::Debug => "DEBG",
                    Level::Trace => "TRCE",
                };

                writeln!(
                    f,
                    "{timestamp} {level} {msg}",
                    timestamp = entry.time,
                    level = level,
                    msg = entry.message
                )?;
            }
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>//! A wrapper around a Cairo image surface.

use std::{default::Default, fs::File, io::Write};

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, LightUserData, Table, UserData, UserDataMethods, Value};
use tempfile;

use crate::area::{Area, Origin, Size};
use crate::common::{
    class::{self, Class},
    object::{self, Object},
    property::Property
};
use crate::wayland_obj::{self, XdgToplevel};

#[derive(Debug)]
pub struct DrawableState {
    temp_file: File,
    wayland_shell: Option<XdgToplevel>,
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub type Drawable<'lua> = Object<'lua, DrawableState>;

impl Default for DrawableState {
    fn default() -> Self {
        let temp_file = tempfile::tempfile().expect("Could not make a temp file for the buffer");
        DrawableState {
            temp_file,
            wayland_shell: None,
            surface: None,
            geo: Area::default(),
            refreshed: false
        }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: rlua::Context<'lua>) -> rlua::Result<Drawable> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref image) => {
                let stash = image.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, lua: rlua::Context<'lua>, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let obj_clone = self.clone();
        let mut drawable = self.state_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.refreshed = false;
            drawable.surface = None;
            drawable.wayland_shell = Some(
                wayland_obj::create_xdg_toplevel(None)
                    .expect("Could not construct an xdg toplevel for a drawable")
            );
            let size: Size = geometry.size;

            if size.width > 0 && size.height > 0 {
                let temp_file = tempfile::tempfile().expect("Could not make new temp file");
                temp_file
                    .set_len(size.width as u64 * size.height as u64 * 4)
                    .expect("Could not set file length");
                drawable.surface = Some(
                    ImageSurface::create(Format::ARgb32, size.width as i32, size.height as i32)
                        .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?
                );
                {
                    let shell = drawable.wayland_shell.as_mut().unwrap();
                    shell.set_size(size);
                    shell
                        .set_surface(&temp_file, size)
                        .map_err(|_| RuntimeError(format!("Could not set surface for drawable")))?;
                }
                drawable.temp_file = temp_file;
                Object::emit_signal(lua, &obj_clone, "property::surface".into(), Value::Nil)?;
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.state_mut()?;
        let drawable = &mut *drawable;
        if let Some(data) = drawable.surface.as_mut().map(get_data) {
            drawable
                .temp_file
                .write(&*data)
                .expect("Could not write data to buffer");
            drawable.temp_file.flush().expect("Could not flush buffer");
            drawable.refreshed = true;
        }
        Ok(())
    }
}

impl UserData for DrawableState {
    fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: rlua::Context) -> rlua::Result<Class<DrawableState>> {
    Class::<DrawableState>::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new(
            "surface".into(),
            None,
            Some(lua.create_function(get_surface)?),
            None
        ))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: rlua::Context<'lua>, drawable: Drawable<'lua>) -> rlua::Result<Value<'lua>> {
    drawable.get_surface()
}

fn geometry<'lua>(lua: rlua::Context<'lua>, drawable: Drawable<'lua>) -> rlua::Result<Table<'lua>> {
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: rlua::Context<'lua>, mut drawable: Drawable<'lua>) -> rlua::Result<()> {
    drawable.refresh()
}

/// Get the data associated with the ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    // NOTE This is safe to do because there's one thread.
    //
    // We know Lua is not modifying it because it's not running.
    use cairo_sys;
    use std::slice;
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<commit_msg>Removed redundant import<commit_after>//! A wrapper around a Cairo image surface.

use std::{default::Default, fs::File, io::Write};

use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, LightUserData, Table, UserData, UserDataMethods, Value};
use tempfile;

use crate::area::{Area, Origin, Size};
use crate::common::{
    class::{self, Class},
    object::{self, Object},
    property::Property
};
use crate::wayland_obj::{self, XdgToplevel};

#[derive(Debug)]
pub struct DrawableState {
    temp_file: File,
    wayland_shell: Option<XdgToplevel>,
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub type Drawable<'lua> = Object<'lua, DrawableState>;

impl Default for DrawableState {
    fn default() -> Self {
        let temp_file = tempfile::tempfile().expect("Could not make a temp file for the buffer");
        DrawableState {
            temp_file,
            wayland_shell: None,
            surface: None,
            geo: Area::default(),
            refreshed: false
        }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: rlua::Context<'lua>) -> rlua::Result<Drawable> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref image) => {
                let stash = image.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, lua: rlua::Context<'lua>, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let obj_clone = self.clone();
        let mut drawable = self.state_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.refreshed = false;
            drawable.surface = None;
            drawable.wayland_shell = Some(
                wayland_obj::create_xdg_toplevel(None)
                    .expect("Could not construct an xdg toplevel for a drawable")
            );
            let size: Size = geometry.size;

            if size.width > 0 && size.height > 0 {
                let temp_file = tempfile::tempfile().expect("Could not make new temp file");
                temp_file
                    .set_len(size.width as u64 * size.height as u64 * 4)
                    .expect("Could not set file length");
                drawable.surface = Some(
                    ImageSurface::create(Format::ARgb32, size.width as i32, size.height as i32)
                        .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?
                );
                {
                    let shell = drawable.wayland_shell.as_mut().unwrap();
                    shell.set_size(size);
                    shell
                        .set_surface(&temp_file, size)
                        .map_err(|_| RuntimeError(format!("Could not set surface for drawable")))?;
                }
                drawable.temp_file = temp_file;
                Object::emit_signal(lua, &obj_clone, "property::surface".into(), Value::Nil)?;
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.state_mut()?;
        let drawable = &mut *drawable;
        if let Some(data) = drawable.surface.as_mut().map(get_data) {
            drawable
                .temp_file
                .write(&*data)
                .expect("Could not write data to buffer");
            drawable.temp_file.flush().expect("Could not flush buffer");
            drawable.refreshed = true;
        }
        Ok(())
    }
}

impl UserData for DrawableState {
    fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: rlua::Context) -> rlua::Result<Class<DrawableState>> {
    Class::<DrawableState>::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new(
            "surface".into(),
            None,
            Some(lua.create_function(get_surface)?),
            None
        ))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: rlua::Context<'lua>, drawable: Drawable<'lua>) -> rlua::Result<Value<'lua>> {
    drawable.get_surface()
}

fn geometry<'lua>(lua: rlua::Context<'lua>, drawable: Drawable<'lua>) -> rlua::Result<Table<'lua>> {
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: rlua::Context<'lua>, mut drawable: Drawable<'lua>) -> rlua::Result<()> {
    drawable.refresh()
}

/// Get the data associated with the ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    // NOTE This is safe to do because there's one thread.
    //
    // We know Lua is not modifying it because it's not running.
    use std::slice;
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};

// See https://developer.android.com/ndk/guides/abis.html#v7a
// for target ABI requirements.

pub fn target() -> TargetResult {
    let mut base = super::android_base::opts();
    base.features = "+v7,+thumb2,+vfp3,+d16,-neon".to_string();
    base.max_atomic_width = Some(64);
    base.pre_link_args
        .get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());

    Ok(Target {
        llvm_target: "armv7-none-linux-android".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        target_os: "android".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        options: TargetOptions {
            abi_blacklist: super::arm_base::abi_blacklist(),
            .. base
        },
    })
}
<commit_msg>Rollup merge of #44589 - makotokato:thumb2, r=alexcrichton<commit_after>// Copyright 2016 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.

use LinkerFlavor;
use target::{Target, TargetOptions, TargetResult};

// See https://developer.android.com/ndk/guides/abis.html#v7a
// for target ABI requirements.

pub fn target() -> TargetResult {
    let mut base = super::android_base::opts();
    base.features = "+v7,+thumb-mode,+thumb2,+vfp3,+d16,-neon".to_string();
    base.max_atomic_width = Some(64);
    base.pre_link_args
        .get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());

    Ok(Target {
        llvm_target: "armv7-none-linux-android".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        target_os: "android".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        options: TargetOptions {
            abi_blacklist: super::arm_base::abi_blacklist(),
            .. base
        },
    })
}
<|endoftext|>