<commit_before>//! Cranelift IR builder library.
//!
//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions
//! corresponding to your source program written in another language.
//!
//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and
//! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html).
//!
//! # Mutable variables and Cranelift IR values
//!
//! The most interesting feature of this API is that it provides a single way to deal with all your
//! variable problems. Indeed, the [`FunctionBuilder`](struct.FunctionBuilder.html) struct has a
//! type `Variable` that should be an index of your source language variables. Then, through
//! calling the functions
//! [`declare_var`](struct.FunctionBuilder.html#method.declare_var),
//! [`def_var`](struct.FunctionBuilder.html#method.def_var) and
//! [`use_var`](struct.FunctionBuilder.html#method.use_var), the
//! [`FunctionBuilder`](struct.FunctionBuilder.html) will create for you all the Cranelift IR
//! values corresponding to your variables.
//!
//! This API has been designed to help you translate your mutable variables into
//! [`SSA`](https://en.wikipedia.org/wiki/Static_single_assignment_form) form.
//! [`use_var`](struct.FunctionBuilder.html#method.use_var) will returns the Cranelift IR value
//! that corresponds to your mutable variable at a precise point in the program. However, you know
//! beforehand that one of your variables is defined only once, for instance if it is the result
//! of an intermediate expression in an expression-based language, then you can translate it
//! directly by the Cranelift IR value returned by the instruction builder. Using the
//! [`use_var`](struct.FunctionBuilder.html#method.use_var) API for such an immutable variable
//! would also work but with a slight additional overhead (the SSA algorithm does not know
//! beforehand if a variable is immutable or not).
//!
//! The moral is that you should use these three functions to handle all your mutable variables,
//! even those that are not present in the source code but artefacts of the translation. It is up
//! to you to keep a mapping between the mutable variables of your language and their `Variable`
//! index that is used by Cranelift. Caution: as the `Variable` is used by Cranelift to index an
//! array containing information about your mutable variables, when you create a new `Variable`
//! with [`Variable::new(var_index)`] you should make sure that `var_index` is provided by a
//! counter incremented by 1 each time you encounter a new mutable variable.
//!
//! # Example
//!
//! Here is a pseudo-program we want to transform into Cranelift IR:
//!
//! ```clif
//! function(x) {
//! x, y, z : i32
//! block0:
//!    y = 2;
//!    z = x + y;
//!    jump block1
//! block1:
//!    z = z + y;
//!    brnz y, block2;
//!    z = z - x;
//!    return y
//! block2:
//!    y = y - x
//!    jump block1
//! }
//! ```
//!
//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`:
//!
//! ```rust
//! extern crate cranelift_codegen;
//! extern crate cranelift_frontend;
//!
//! use cranelift_codegen::entity::EntityRef;
//! use cranelift_codegen::ir::types::*;
//! use cranelift_codegen::ir::{AbiParam, ExternalName, Function, InstBuilder, Signature};
//! use cranelift_codegen::isa::CallConv;
//! use cranelift_codegen::settings;
//! use cranelift_codegen::verifier::verify_function;
//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
//!
//! fn main() {
//!     let mut sig = Signature::new(CallConv::SystemV);
//!     sig.returns.push(AbiParam::new(I32));
//!     sig.params.push(AbiParam::new(I32));
//!     let mut fn_builder_ctx = FunctionBuilderContext::new();
//!     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
//!     {
//!         let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
//!
//!         let block0 = builder.create_ebb();
//!         let block1 = builder.create_ebb();
//!         let block2 = builder.create_ebb();
//!         let x = Variable::new(0);
//!         let y = Variable::new(1);
//!         let z = Variable::new(2);
//!         builder.declare_var(x, I32);
//!         builder.declare_var(y, I32);
//!         builder.declare_var(z, I32);
//!         builder.append_ebb_params_for_function_params(block0);
//!
//!         builder.switch_to_block(block0);
//!         builder.seal_block(block0);
//!         {
//!             let tmp = builder.ebb_params(block0)[0]; // the first function parameter
//!             builder.def_var(x, tmp);
//!         }
//!         {
//!             let tmp = builder.ins().iconst(I32, 2);
//!             builder.def_var(y, tmp);
//!         }
//!         {
//!             let arg1 = builder.use_var(x);
//!             let arg2 = builder.use_var(y);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!
//!         builder.switch_to_block(block1);
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(z);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().brnz(arg, block2, &[]);
//!         }
//!         {
//!             let arg1 = builder.use_var(z);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().return_(&[arg]);
//!         }
//!
//!         builder.switch_to_block(block2);
//!         builder.seal_block(block2);
//!
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(y, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!         builder.seal_block(block1);
//!
//!         builder.finalize();
//!     }
//!
//!     let flags = settings::Flags::new(settings::builder());
//!     let res = verify_function(&func, &flags);
//!     println!("{}", func.display(None));
//!     if let Err(errors) = res {
//!         panic!("{}", errors);
//!     }
//! }
//! ```

#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "std", deny(unstable_features))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        clippy::float_arithmetic,
        clippy::mut_mut,
        clippy::nonminimal_bool,
        clippy::option_map_unwrap_or,
        clippy::option_map_unwrap_or_else,
        clippy::print_stdout,
        clippy::unicode_not_nfc,
        clippy::use_self
    )
)]
#![no_std]
#![cfg_attr(not(feature = "std"), feature(alloc))]

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc as std;
#[cfg(feature = "std")]
#[macro_use]
extern crate std;

#[cfg(not(feature = "std"))]
use hashmap_core::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;

pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext};
pub use crate::switch::Switch;
pub use crate::variable::Variable;

mod frontend;
mod ssa;
mod switch;
mod variable;

/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
<commit_msg>fix typos in cranelift-frontend/src/lib.rs<commit_after>//! Cranelift IR builder library.
//!
//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions
//! corresponding to your source program written in another language.
//!
//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and
//! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html).
//!
//! # Mutable variables and Cranelift IR values
//!
//! The most interesting feature of this API is that it provides a single way to deal with all your
//! variable problems. Indeed, the [`FunctionBuilder`](struct.FunctionBuilder.html) struct has a
//! type `Variable` that should be an index of your source language variables. Then, through
//! calling the functions
//! [`declare_var`](struct.FunctionBuilder.html#method.declare_var),
//! [`def_var`](struct.FunctionBuilder.html#method.def_var) and
//! [`use_var`](struct.FunctionBuilder.html#method.use_var), the
//! [`FunctionBuilder`](struct.FunctionBuilder.html) will create for you all the Cranelift IR
//! values corresponding to your variables.
//!
//! This API has been designed to help you translate your mutable variables into
//! [`SSA`](https://en.wikipedia.org/wiki/Static_single_assignment_form) form.
//! [`use_var`](struct.FunctionBuilder.html#method.use_var) will return the Cranelift IR value
//! that corresponds to your mutable variable at a precise point in the program. However, if you know
//! beforehand that one of your variables is defined only once, for instance if it is the result
//! of an intermediate expression in an expression-based language, then you can translate it
//! directly by the Cranelift IR value returned by the instruction builder. Using the
//! [`use_var`](struct.FunctionBuilder.html#method.use_var) API for such an immutable variable
//! would also work but with a slight additional overhead (the SSA algorithm does not know
//! beforehand if a variable is immutable or not).
//!
//! The moral is that you should use these three functions to handle all your mutable variables,
//! even those that are not present in the source code but artifacts of the translation. It is up
//! to you to keep a mapping between the mutable variables of your language and their `Variable`
//! index that is used by Cranelift. Caution: as the `Variable` is used by Cranelift to index an
//! array containing information about your mutable variables, when you create a new `Variable`
//! with [`Variable::new(var_index)`] you should make sure that `var_index` is provided by a
//! counter incremented by 1 each time you encounter a new mutable variable.
//!
//! # Example
//!
//! Here is a pseudo-program we want to transform into Cranelift IR:
//!
//! ```clif
//! function(x) {
//! x, y, z : i32
//! block0:
//!    y = 2;
//!    z = x + y;
//!    jump block1
//! block1:
//!    z = z + y;
//!    brnz y, block2;
//!    z = z - x;
//!    return y
//! block2:
//!    y = y - x
//!    jump block1
//! }
//! ```
//!
//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`:
//!
//! ```rust
//! extern crate cranelift_codegen;
//! extern crate cranelift_frontend;
//!
//! use cranelift_codegen::entity::EntityRef;
//! use cranelift_codegen::ir::types::*;
//! use cranelift_codegen::ir::{AbiParam, ExternalName, Function, InstBuilder, Signature};
//! use cranelift_codegen::isa::CallConv;
//! use cranelift_codegen::settings;
//! use cranelift_codegen::verifier::verify_function;
//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
//!
//! fn main() {
//!     let mut sig = Signature::new(CallConv::SystemV);
//!     sig.returns.push(AbiParam::new(I32));
//!     sig.params.push(AbiParam::new(I32));
//!     let mut fn_builder_ctx = FunctionBuilderContext::new();
//!     let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig);
//!     {
//!         let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
//!
//!         let block0 = builder.create_ebb();
//!         let block1 = builder.create_ebb();
//!         let block2 = builder.create_ebb();
//!         let x = Variable::new(0);
//!         let y = Variable::new(1);
//!         let z = Variable::new(2);
//!         builder.declare_var(x, I32);
//!         builder.declare_var(y, I32);
//!         builder.declare_var(z, I32);
//!         builder.append_ebb_params_for_function_params(block0);
//!
//!         builder.switch_to_block(block0);
//!         builder.seal_block(block0);
//!         {
//!             let tmp = builder.ebb_params(block0)[0]; // the first function parameter
//!             builder.def_var(x, tmp);
//!         }
//!         {
//!             let tmp = builder.ins().iconst(I32, 2);
//!             builder.def_var(y, tmp);
//!         }
//!         {
//!             let arg1 = builder.use_var(x);
//!             let arg2 = builder.use_var(y);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!
//!         builder.switch_to_block(block1);
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(z);
//!             let tmp = builder.ins().iadd(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().brnz(arg, block2, &[]);
//!         }
//!         {
//!             let arg1 = builder.use_var(z);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(z, tmp);
//!         }
//!         {
//!             let arg = builder.use_var(y);
//!             builder.ins().return_(&[arg]);
//!         }
//!
//!         builder.switch_to_block(block2);
//!         builder.seal_block(block2);
//!
//!         {
//!             let arg1 = builder.use_var(y);
//!             let arg2 = builder.use_var(x);
//!             let tmp = builder.ins().isub(arg1, arg2);
//!             builder.def_var(y, tmp);
//!         }
//!         builder.ins().jump(block1, &[]);
//!         builder.seal_block(block1);
//!
//!         builder.finalize();
//!     }
//!
//!     let flags = settings::Flags::new(settings::builder());
//!     let res = verify_function(&func, &flags);
//!     println!("{}", func.display(None));
//!     if let Err(errors) = res {
//!         panic!("{}", errors);
//!     }
//! }
//! ```

#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(feature = "std", deny(unstable_features))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        clippy::float_arithmetic,
        clippy::mut_mut,
        clippy::nonminimal_bool,
        clippy::option_map_unwrap_or,
        clippy::option_map_unwrap_or_else,
        clippy::print_stdout,
        clippy::unicode_not_nfc,
        clippy::use_self
    )
)]
#![no_std]
#![cfg_attr(not(feature = "std"), feature(alloc))]

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc as std;
#[cfg(feature = "std")]
#[macro_use]
extern crate std;

#[cfg(not(feature = "std"))]
use hashmap_core::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;

pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext};
pub use crate::switch::Switch;
pub use crate::variable::Variable;

mod frontend;
mod ssa;
mod switch;
mod variable;

/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
<|endoftext|>


<commit_before>use hir::Semantics;
use ide_db::{
    base_db::{FileId, FilePosition, FileRange, SourceDatabase},
    RootDatabase, SymbolKind,
};
use syntax::TextRange;

use crate::{
    file_structure::file_structure,
    fn_references::find_all_methods,
    goto_implementation::goto_implementation,
    references::find_all_refs,
    runnables::{runnables, Runnable},
    NavigationTarget, RunnableKind,
};

// Feature: Annotations
//
// Provides user with annotations above items for looking up references or impl blocks
// and running/debugging binaries.
pub struct Annotation {
    pub range: TextRange,
    pub kind: AnnotationKind,
}

pub enum AnnotationKind {
    Runnable { debug: bool, runnable: Runnable },
    HasImpls { position: FilePosition, data: Option<Vec<NavigationTarget>> },
    HasReferences { position: FilePosition, data: Option<Vec<FileRange>> },
}

pub struct AnnotationConfig {
    pub binary_target: bool,
    pub annotate_runnables: bool,
    pub annotate_impls: bool,
    pub annotate_references: bool,
    pub annotate_method_references: bool,
    pub run: bool,
    pub debug: bool,
}

pub(crate) fn annotations(
    db: &RootDatabase,
    file_id: FileId,
    config: AnnotationConfig,
) -> Vec<Annotation> {
    let mut annotations = Vec::default();

    if config.annotate_runnables {
        for runnable in runnables(db, file_id) {
            if !matches!(runnable.kind, RunnableKind::Bin) || !config.binary_target {
                continue;
            }

            let action = runnable.action();
            let range = runnable.nav.full_range;

            if config.run {
                annotations.push(Annotation {
                    range,
                    // FIXME: This one allocates without reason if run is enabled, but debug is disabled
                    kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() },
                });
            }

            if action.debugee && config.debug {
                annotations.push(Annotation {
                    range,
                    kind: AnnotationKind::Runnable { debug: true, runnable },
                });
            }
        }
    }

    file_structure(&db.parse(file_id).tree())
        .into_iter()
        .filter(|node| {
            matches!(
                node.kind,
                SymbolKind::Trait
                    | SymbolKind::Struct
                    | SymbolKind::Enum
                    | SymbolKind::Union
                    | SymbolKind::Const
            )
        })
        .for_each(|node| {
            if config.annotate_impls && node.kind != SymbolKind::Const {
                annotations.push(Annotation {
                    range: node.node_range,
                    kind: AnnotationKind::HasImpls {
                        position: FilePosition { file_id, offset: node.navigation_range.start() },
                        data: None,
                    },
                });
            }

            if config.annotate_references {
                annotations.push(Annotation {
                    range: node.node_range,
                    kind: AnnotationKind::HasReferences {
                        position: FilePosition { file_id, offset: node.navigation_range.start() },
                        data: None,
                    },
                });
            }
        });

    if config.annotate_method_references {
        annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation {
            range: method.range,
            kind: AnnotationKind::HasReferences {
                position: FilePosition { file_id, offset: method.range.start() },
                data: None,
            },
        }));
    }

    annotations
}

pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
    match annotation.kind {
        AnnotationKind::HasImpls { position, ref mut data } => {
            *data = goto_implementation(db, position).map(|range| range.info);
        }
        AnnotationKind::HasReferences { position, ref mut data } => {
            *data = find_all_refs(&Semantics::new(db), position, None).map(|result| {
                result
                    .references
                    .into_iter()
                    .map(|(file_id, access)| {
                        access.into_iter().map(move |(range, _)| FileRange { file_id, range })
                    })
                    .flatten()
                    .collect()
            });
        }
        _ => {}
    };

    annotation
}
<commit_msg>Added annotation tests<commit_after>use hir::Semantics;
use ide_db::{
    base_db::{FileId, FilePosition, FileRange, SourceDatabase},
    RootDatabase, SymbolKind,
};
use syntax::TextRange;

use crate::{
    file_structure::file_structure,
    fn_references::find_all_methods,
    goto_implementation::goto_implementation,
    references::find_all_refs,
    runnables::{runnables, Runnable},
    NavigationTarget, RunnableKind,
};

// Feature: Annotations
//
// Provides user with annotations above items for looking up references or impl blocks
// and running/debugging binaries.
#[derive(Debug)]
pub struct Annotation {
    pub range: TextRange,
    pub kind: AnnotationKind,
}

#[derive(Debug)]
pub enum AnnotationKind {
    Runnable { debug: bool, runnable: Runnable },
    HasImpls { position: FilePosition, data: Option<Vec<NavigationTarget>> },
    HasReferences { position: FilePosition, data: Option<Vec<FileRange>> },
}

pub struct AnnotationConfig {
    pub binary_target: bool,
    pub annotate_runnables: bool,
    pub annotate_impls: bool,
    pub annotate_references: bool,
    pub annotate_method_references: bool,
    pub run: bool,
    pub debug: bool,
}

pub(crate) fn annotations(
    db: &RootDatabase,
    file_id: FileId,
    config: AnnotationConfig,
) -> Vec<Annotation> {
    let mut annotations = Vec::default();

    if config.annotate_runnables {
        for runnable in runnables(db, file_id) {
            if !matches!(runnable.kind, RunnableKind::Bin) || !config.binary_target {
                continue;
            }

            let action = runnable.action();
            let range = runnable.nav.full_range;

            if config.run {
                annotations.push(Annotation {
                    range,
                    // FIXME: This one allocates without reason if run is enabled, but debug is disabled
                    kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() },
                });
            }

            if action.debugee && config.debug {
                annotations.push(Annotation {
                    range,
                    kind: AnnotationKind::Runnable { debug: true, runnable },
                });
            }
        }
    }

    file_structure(&db.parse(file_id).tree())
        .into_iter()
        .filter(|node| {
            matches!(
                node.kind,
                SymbolKind::Trait
                    | SymbolKind::Struct
                    | SymbolKind::Enum
                    | SymbolKind::Union
                    | SymbolKind::Const
            )
        })
        .for_each(|node| {
            if config.annotate_impls && node.kind != SymbolKind::Const {
                annotations.push(Annotation {
                    range: node.node_range,
                    kind: AnnotationKind::HasImpls {
                        position: FilePosition { file_id, offset: node.navigation_range.start() },
                        data: None,
                    },
                });
            }

            if config.annotate_references {
                annotations.push(Annotation {
                    range: node.node_range,
                    kind: AnnotationKind::HasReferences {
                        position: FilePosition { file_id, offset: node.navigation_range.start() },
                        data: None,
                    },
                });
            }
        });

    if config.annotate_method_references {
        annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation {
            range: method.range,
            kind: AnnotationKind::HasReferences {
                position: FilePosition { file_id, offset: method.range.start() },
                data: None,
            },
        }));
    }

    annotations
}

pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
    match annotation.kind {
        AnnotationKind::HasImpls { position, ref mut data } => {
            *data = goto_implementation(db, position).map(|range| range.info);
        }
        AnnotationKind::HasReferences { position, ref mut data } => {
            *data = find_all_refs(&Semantics::new(db), position, None).map(|result| {
                result
                    .references
                    .into_iter()
                    .map(|(file_id, access)| {
                        access.into_iter().map(move |(range, _)| FileRange { file_id, range })
                    })
                    .flatten()
                    .collect()
            });
        }
        _ => {}
    };

    annotation
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::{FileId, FileRange};
    use syntax::{TextRange, TextSize};

    use crate::{fixture, Annotation, AnnotationConfig, AnnotationKind, RunnableKind};

    fn get_annotations(
        ra_fixture: &str,
        annotation_config: AnnotationConfig,
    ) -> (FileId, Vec<Annotation>) {
        let (analysis, file_id) = fixture::file(ra_fixture);

        let annotations: Vec<Annotation> = analysis
            .annotations(file_id, annotation_config)
            .unwrap()
            .into_iter()
            .map(move |annotation| analysis.resolve_annotation(annotation).unwrap())
            .collect();

        if annotations.len() == 0 {
            panic!("unresolved annotations")
        }

        (file_id, annotations)
    }

    macro_rules! check_annotation {
        ( $ra_fixture:expr, $config:expr, $item_positions:expr, $pattern:pat, $checker:expr ) => {
            let (file_id, annotations) = get_annotations($ra_fixture, $config);

            annotations.into_iter().for_each(|annotation| {
                assert!($item_positions.contains(&annotation.range));

                match annotation.kind {
                    $pattern => $checker(file_id),
                    _ => panic!("Unexpected annotation kind"),
                }
            });
        };
    }

    #[test]
    fn const_annotations() {
        check_annotation!(
            r#"
const DEMO: i32 = 123;

fn main() {
    let hello = DEMO;
}
            "#,
            AnnotationConfig {
                binary_target: false,
                annotate_runnables: false,
                annotate_impls: false,
                annotate_references: true,
                annotate_method_references: false,
                run: false,
                debug: false,
            },
            &[TextRange::new(TextSize::from(0), TextSize::from(22))],
            AnnotationKind::HasReferences { data: Some(ranges), .. },
            |file_id| assert_eq!(
                *ranges.first().unwrap(),
                FileRange {
                    file_id,
                    range: TextRange::new(TextSize::from(52), TextSize::from(56))
                }
            )
        );
    }

    #[test]
    fn unused_const_annotations() {
        check_annotation!(
            r#"
const DEMO: i32 = 123;

fn main() {}
            "#,
            AnnotationConfig {
                binary_target: false,
                annotate_runnables: false,
                annotate_impls: false,
                annotate_references: true,
                annotate_method_references: false,
                run: false,
                debug: false,
            },
            &[TextRange::new(TextSize::from(0), TextSize::from(22))],
            AnnotationKind::HasReferences { data: Some(ranges), .. },
            |_| assert_eq!(ranges.len(), 0)
        );
    }

    #[test]
    fn struct_references_annotations() {
        check_annotation!(
            r#"
struct Test;

fn main() {
    let test = Test;
}
            "#,
            AnnotationConfig {
                binary_target: false,
                annotate_runnables: false,
                annotate_impls: false,
                annotate_references: true,
                annotate_method_references: false,
                run: false,
                debug: false,
            },
            &[TextRange::new(TextSize::from(0), TextSize::from(12))],
            AnnotationKind::HasReferences { data: Some(ranges), .. },
            |file_id| assert_eq!(
                *ranges.first().unwrap(),
                FileRange {
                    file_id,
                    range: TextRange::new(TextSize::from(41), TextSize::from(45))
                }
            )
        );
    }

    #[test]
    fn struct_and_trait_impls_annotations() {
        check_annotation!(
            r#"
struct Test;

trait MyCoolTrait {}

impl MyCoolTrait for Test {}

fn main() {
    let test = Test;
}
            "#,
            AnnotationConfig {
                binary_target: false,
                annotate_runnables: false,
                annotate_impls: true,
                annotate_references: false,
                annotate_method_references: false,
                run: false,
                debug: false,
            },
            &[
                TextRange::new(TextSize::from(0), TextSize::from(12)),
                TextRange::new(TextSize::from(14), TextSize::from(34))
            ],
            AnnotationKind::HasImpls { data: Some(ranges), .. },
            |_| assert_eq!(
                ranges.first().unwrap().full_range,
                TextRange::new(TextSize::from(36), TextSize::from(64))
            )
        );
    }

    #[test]
    fn run_annotation() {
        check_annotation!(
            r#"
fn main() {}
            "#,
            AnnotationConfig {
                binary_target: true,
                annotate_runnables: true,
                annotate_impls: false,
                annotate_references: false,
                annotate_method_references: false,
                run: true,
                debug: false,
            },
            &[TextRange::new(TextSize::from(0), TextSize::from(12))],
            AnnotationKind::Runnable { debug: false, runnable },
            |_| {
                assert!(matches!(runnable.kind, RunnableKind::Bin));
                assert!(runnable.action().run_title.contains("Run"));
            }
        );
    }

    #[test]
    fn debug_annotation() {
        check_annotation!(
            r#"
fn main() {}
            "#,
            AnnotationConfig {
                binary_target: true,
                annotate_runnables: true,
                annotate_impls: false,
                annotate_references: false,
                annotate_method_references: false,
                run: false,
                debug: true,
            },
            &[TextRange::new(TextSize::from(0), TextSize::from(12))],
            AnnotationKind::Runnable { debug: true, runnable },
            |_| {
                assert!(matches!(runnable.kind, RunnableKind::Bin));
                assert!(runnable.action().debugee);
            }
        );
    }

    #[test]
    fn method_annotations() {
        // We actually want to skip `fn main` annotation, as it has no references in it
        // but just ignoring empty reference slices would lead to false-positive if something
        // goes wrong in annotation resolving mechanism. By tracking if we iterated before finding
        // an empty slice we can track if everything is settled.
        let mut iterated_once = false;

        check_annotation!(
            r#"
struct Test;

impl Test {
    fn self_by_ref(&self) {}
}

fn main() {
    Test.self_by_ref();
}
            "#,
            AnnotationConfig {
                binary_target: false,
                annotate_runnables: false,
                annotate_impls: false,
                annotate_references: false,
                annotate_method_references: true,
                run: false,
                debug: false,
            },
            &[
                TextRange::new(TextSize::from(33), TextSize::from(44)),
                TextRange::new(TextSize::from(61), TextSize::from(65))
            ],
            AnnotationKind::HasReferences { data: Some(ranges), .. },
            |file_id| {
                match ranges.as_slice() {
                    [first, ..] => {
                        assert_eq!(
                            *first,
                            FileRange {
                                file_id,
                                range: TextRange::new(TextSize::from(79), TextSize::from(90))
                            }
                        );

                        iterated_once = true;
                    }
                    [] if iterated_once => {}
                    [] => panic!("One reference was expected but not found"),
                }
            }
        );
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io::Write;

use error::{Error, Result, ResultLiquidChainExt};
use value::Path;
use value::Scalar;

use super::Context;
use super::Expression;
use super::Renderable;

/// A `Value` reference.
#[derive(Clone, Debug, PartialEq)]
pub struct Variable {
    variable: Scalar,
    indexes: Vec<Expression>,
}

impl Variable {
    /// Create a `Value` reference.
    pub fn with_literal<S: Into<Scalar>>(value: S) -> Self {
        Self {
            variable: value.into(),
            indexes: Default::default(),
        }
    }

    /// Append a literal.
    pub fn push_literal<S: Into<Scalar>>(mut self, value: S) -> Self {
        self.indexes.push(Expression::with_literal(value));
        self
    }

    /// Convert to a `Path`.
    pub fn try_evaluate<'c>(&'c self, context: &'c Context) -> Option<Path<'c>> {
        let mut path = Path::with_index(self.variable.as_ref());
        path.reserve(self.indexes.len());
        for expr in &self.indexes {
            let v = expr.try_evaluate(context)?;
            let s = v.as_scalar()?.as_ref();
            path.push(s);
        }
        Some(path)
    }

    /// Convert to a `Path`.
    pub fn evaluate<'c>(&'c self, context: &'c Context) -> Result<Path<'c>> {
        let mut path = Path::with_index(self.variable.as_ref());
        path.reserve(self.indexes.len());
        for expr in &self.indexes {
            let v = expr.evaluate(context)?;
            let s = v
                .as_scalar()
                .ok_or_else(|| Error::with_msg(format!("Expected scalar, found `{}`", v)))?
                .as_ref();
            path.push(s);
        }
        Ok(path)
    }
}

impl Extend<Scalar> for Variable {
    fn extend<T: IntoIterator<Item = Scalar>>(&mut self, iter: T) {
        let path = iter.into_iter().map(Expression::with_literal);
        self.indexes.extend(path);
    }
}

impl Extend<Expression> for Variable {
    fn extend<T: IntoIterator<Item = Expression>>(&mut self, iter: T) {
        let path = iter.into_iter();
        self.indexes.extend(path);
    }
}

impl fmt::Display for Variable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.variable)?;
        for index in self.indexes.iter() {
            write!(f, "[{}]", index)?;
        }
        Ok(())
    }
}

impl Renderable for Variable {
    fn render_to(&self, writer: &mut Write, context: &mut Context) -> Result<()> {
        let path = self.evaluate(context)?;
        let value = context.stack().get(&path)?;
        write!(writer, "{}", value).chain("Failed to render")?;
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use serde_yaml;

    use super::super::ContextBuilder;
    use super::*;
    use value::Object;

    #[test]
    fn identifier_path_array_index() {
        let globals: Object = serde_yaml::from_str(
            r#"
test_a: ["test"]
"#,
        )
        .unwrap();
        let mut actual = Variable::with_literal("test_a");
        let index = vec![Scalar::new(0)];
        actual.extend(index);

        let mut context = ContextBuilder::new().set_globals(&globals).build();
        let actual = actual.render(&mut context).unwrap();
        assert_eq!(actual, "test".to_owned());
    }

    #[test]
    fn identifier_path_array_index_negative() {
        let globals: Object = serde_yaml::from_str(
            r#"
test_a: ["test1", "test2"]
"#,
        )
        .unwrap();
        let mut actual = Variable::with_literal("test_a");
        let index = vec![Scalar::new(-1)];
        actual.extend(index);

        let mut context = ContextBuilder::new().set_globals(&globals).build();
        let actual = actual.render(&mut context).unwrap();
        assert_eq!(actual, "test2".to_owned());
    }

    #[test]
    fn identifier_path_object() {
        let globals: Object = serde_yaml::from_str(
            r#"
test_a:
  - test_h: 5
"#,
        )
        .unwrap();
        let mut actual = Variable::with_literal("test_a");
        let index = vec![Scalar::new(0), Scalar::new("test_h")];
        actual.extend(index);

        let mut context = ContextBuilder::new().set_globals(&globals).build();
        let actual = actual.render(&mut context).unwrap();
        assert_eq!(actual, "5".to_owned());
    }
}
<commit_msg>fix(variabl): Remove unused Render<commit_after>use std::fmt;

use error::{Error, Result};
use value::Path;
use value::Scalar;

use super::Context;
use super::Expression;

/// A `Value` reference.
#[derive(Clone, Debug, PartialEq)]
pub struct Variable {
    variable: Scalar,
    indexes: Vec<Expression>,
}

impl Variable {
    /// Create a `Value` reference.
    pub fn with_literal<S: Into<Scalar>>(value: S) -> Self {
        Self {
            variable: value.into(),
            indexes: Default::default(),
        }
    }

    /// Append a literal.
    pub fn push_literal<S: Into<Scalar>>(mut self, value: S) -> Self {
        self.indexes.push(Expression::with_literal(value));
        self
    }

    /// Convert to a `Path`.
    pub fn try_evaluate<'c>(&'c self, context: &'c Context) -> Option<Path<'c>> {
        let mut path = Path::with_index(self.variable.as_ref());
        path.reserve(self.indexes.len());
        for expr in &self.indexes {
            let v = expr.try_evaluate(context)?;
            let s = v.as_scalar()?.as_ref();
            path.push(s);
        }
        Some(path)
    }

    /// Convert to a `Path`.
    pub fn evaluate<'c>(&'c self, context: &'c Context) -> Result<Path<'c>> {
        let mut path = Path::with_index(self.variable.as_ref());
        path.reserve(self.indexes.len());
        for expr in &self.indexes {
            let v = expr.evaluate(context)?;
            let s = v
                .as_scalar()
                .ok_or_else(|| Error::with_msg(format!("Expected scalar, found `{}`", v)))?
                .as_ref();
            path.push(s);
        }
        Ok(path)
    }
}

impl Extend<Scalar> for Variable {
    fn extend<T: IntoIterator<Item = Scalar>>(&mut self, iter: T) {
        let path = iter.into_iter().map(Expression::with_literal);
        self.indexes.extend(path);
    }
}

impl Extend<Expression> for Variable {
    fn extend<T: IntoIterator<Item = Expression>>(&mut self, iter: T) {
        let path = iter.into_iter();
        self.indexes.extend(path);
    }
}

impl fmt::Display for Variable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.variable)?;
        for index in self.indexes.iter() {
            write!(f, "[{}]", index)?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use serde_yaml;

    use super::super::ContextBuilder;
    use super::*;
    use value::Object;

    #[test]
    fn identifier_path_array_index() {
        let globals: Object = serde_yaml::from_str(
            r#"
test_a: ["test"]
"#,
        )
        .unwrap();
        let mut var = Variable::with_literal("test_a");
        let index = vec![Scalar::new(0)];
        var.extend(index);

        let context = ContextBuilder::new().set_globals(&globals).build();
        let actual = var.evaluate(&context).unwrap();
        let actual = context.stack().get(&actual).unwrap();
        assert_eq!(actual.to_string(), "test");
    }

    #[test]
    fn identifier_path_array_index_negative() {
        let globals: Object = serde_yaml::from_str(
            r#"
test_a: ["test1", "test2"]
"#,
        )
        .unwrap();
        let mut var = Variable::with_literal("test_a");
        let index = vec![Scalar::new(-1)];
        var.extend(index);

        let context = ContextBuilder::new().set_globals(&globals).build();
        let actual = var.evaluate(&context).unwrap();
        let actual = context.stack().get(&actual).unwrap();
        assert_eq!(actual.to_string(), "test2");
    }

    #[test]
    fn identifier_path_object() {
        let globals: Object = serde_yaml::from_str(
            r#"
test_a:
  - test_h: 5
"#,
        )
        .unwrap();
        let mut var = Variable::with_literal("test_a");
        let index = vec![Scalar::new(0), Scalar::new("test_h")];
        var.extend(index);

        let context = ContextBuilder::new().set_globals(&globals).build();
        let actual = var.evaluate(&context).unwrap();
        let actual = context.stack().get(&actual).unwrap();
        assert_eq!(actual.to_string(), "5");
    }
}
<|endoftext|>


<commit_before>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ast::LitKind;
use crate::utils::{span_lint_and_sugg, snippet_with_applicability, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::max_value() as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.node;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if_chain! {
            if let Some(cv) = result;
            if let Some(to_type) = cv.to_type;

            then {
                let mut applicability = Applicability::MachineApplicable;
                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut
                                applicability);
                span_lint_and_sugg(
                    cx,
                    CHECKED_CONVERSIONS,
                    item.span,
                    "Checked cast can be simplified.",
                    "try",
                    format!("{}::try_from({}).is_ok()",
                            to_type,
                            snippet),
                    applicability
                );
            }
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check(expr: &Expr) -> Option<Conversion<'_>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr, right: &'a Expr) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr,
    to_type: Option<String>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref()).map_or(true, |(l, r)| l == r)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new<'b>(expr_to_cast: &'a Expr, from_type: &'b str, to_type: String) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, &to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    fn try_new(from: &str, to: &str) -> Option<Self> {
        if UNSIGNED_TYPES.contains(&from) {
            Some(ConversionType::FromUnsigned)
        } else if SIGNED_TYPES.contains(&from) {
            if UNSIGNED_TYPES.contains(&to) {
                Some(ConversionType::SignedToUnsigned)
            } else if SIGNED_TYPES.contains(&to) {
                Some(ConversionType::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::max_value() as from_type)`
fn check_upper_bound(expr: &Expr) -> Option<Conversion<'_>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, "max_value", INT_TYPES);

         then {
             Conversion::try_new(candidate, &from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::min_value() as from_type)`
fn check_lower_bound(expr: &Expr) -> Option<Conversion<'_>> {
    fn check_function<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.node;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::min_value() as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, "min_value", SIGNED_TYPES) {
        Conversion::try_new(candidate, &from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast(expr: &Expr, func: &str, types: &[&str]) -> Option<(String, String)> {
    // `to_type::maxmin_value() as from_type`
    let call_from_cast: Option<(&Expr, String)> = if_chain! {
        // to_type::maxmin_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.node;
        if let TyKind::Path(ref from_type_path) = &from_type.node;
        if let Some(from_type_str) = int_ty_to_str(from_type_path);

        then {
            Some((limit, from_type_str.to_string()))
        } else {
            None
        }
    };

    // `from_type::from(to_type::maxmin_value())`
    let limit_from: Option<(&Expr, String)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::maxmin_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.node;
            // `to_type::maxmin_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.node;
            if let Some(from_type) = get_implementing_type(path, INT_TYPES, "from");

            then {
                Some((limit, from_type))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        if_chain! {
            if let ExprKind::Call(ref fun_name, _) = &limit.node;
            // `to_type, maxmin_value`
            if let ExprKind::Path(ref path) = &fun_name.node;
            // `to_type`
            if let Some(to_type) = get_implementing_type(path, types, func);

            then {
                Some((from_type, to_type))
            } else {
                None
            }
        }
    } else {
        None
    }
}

/// Gets the type which implements the called function
fn get_implementing_type(path: &QPath, candidates: &[&str], function: &str) -> Option<String> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.node;
        if let [int] = &*tp.segments;
        let name = int.ident.as_str().get();
        if candidates.contains(&name);

        then {
            Some(name.to_string())
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_str(path: &QPath) -> Option<&str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;

        then {
            INT_TYPES
                .iter()
                .find(|c| (&ty.ident.name) == *c)
                .cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &'a BinOp, left: &'a Expr, right: &'a Expr) -> Option<(&'a Expr, &'a Expr)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

const UNSIGNED_TYPES: &[&str] = &["u8", "u16", "u32", "u64", "u128", "usize"];
const SIGNED_TYPES: &[&str] = &["i8", "i16", "i32", "i64", "i128", "isize"];
const INT_TYPES: &[&str] = &[
    "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize",
];
<commit_msg>Changed impl to use symbols.<commit_after>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use lazy_static::lazy_static;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ast::LitKind;
use syntax::symbol::Symbol;

use crate::utils::{snippet_with_applicability, span_lint_and_sugg, sym, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::max_value() as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.node;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if_chain! {
            if let Some(cv) = result;
            if let Some(to_type) = cv.to_type;

            then {
                let mut applicability = Applicability::MachineApplicable;
                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut
                                applicability);
                span_lint_and_sugg(
                    cx,
                    CHECKED_CONVERSIONS,
                    item.span,
                    "Checked cast can be simplified.",
                    "try",
                    format!("{}::try_from({}).is_ok()",
                            to_type,
                            snippet),
                    applicability
                );
            }
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check(expr: &Expr) -> Option<Conversion<'_>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr, right: &'a Expr) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr,
    to_type: Option<Symbol>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref()).map_or(true, |(l, r)| l == r)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new<'b>(expr_to_cast: &'a Expr, from_type: Symbol, to_type: Symbol) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    fn try_new(from: Symbol, to: Symbol) -> Option<Self> {
        if UINTS.contains(&from) {
            Some(ConversionType::FromUnsigned)
        } else if SINTS.contains(&from) {
            if UINTS.contains(&to) {
                Some(ConversionType::SignedToUnsigned)
            } else if SINTS.contains(&to) {
                Some(ConversionType::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::max_value() as from_type)`
fn check_upper_bound(expr: &Expr) -> Option<Conversion<'_>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, *sym::max_value, &*INTS);

         then {
             Conversion::try_new(candidate, from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::min_value() as from_type)`
fn check_lower_bound(expr: &Expr) -> Option<Conversion<'_>> {
    fn check_function<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.node;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::min_value() as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, *sym::min_value, &*SINTS) {
        Conversion::try_new(candidate, from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast(expr: &Expr, func: Symbol, types: &[Symbol]) -> Option<(Symbol, Symbol)> {
    // `to_type::maxmin_value() as from_type`
    let call_from_cast: Option<(&Expr, Symbol)> = if_chain! {
        // to_type::maxmin_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.node;
        if let TyKind::Path(ref from_type_path) = &from_type.node;
        if let Some(from_sym) = int_ty_to_sym(from_type_path);

        then {
            Some((limit, from_sym))
        } else {
            None
        }
    };

    // `from_type::from(to_type::maxmin_value())`
    let limit_from: Option<(&Expr, Symbol)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::maxmin_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.node;
            // `to_type::maxmin_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.node;
            if let Some(from_sym) = get_implementing_type(path, &*INTS, *sym::from);

            then {
                Some((limit, from_sym))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        if_chain! {
            if let ExprKind::Call(ref fun_name, _) = &limit.node;
            // `to_type, maxmin_value`
            if let ExprKind::Path(ref path) = &fun_name.node;
            // `to_type`
            if let Some(to_type) = get_implementing_type(path, types, func);

            then {
                Some((from_type, to_type))
            } else {
                None
            }
        }
    } else {
        None
    }
}

/// Gets the type which implements the called function
fn get_implementing_type(path: &QPath, candidates: &[Symbol], function: Symbol) -> Option<Symbol> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.node;
        if let [int] = &*tp.segments;
        let name = int.ident.name;
        if candidates.contains(&name);

        then {
            Some(name)
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_sym(path: &QPath) -> Option<Symbol> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;

        then {
            INTS
                .iter()
                .find(|c| ty.ident.name == **c)
                .cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &'a BinOp, left: &'a Expr, right: &'a Expr) -> Option<(&'a Expr, &'a Expr)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

lazy_static! {
    static ref UINTS: [Symbol; 5] = [*sym::u8, *sym::u16, *sym::u32, *sym::u64, *sym::usize];
    static ref SINTS: [Symbol; 5] = [*sym::i8, *sym::i16, *sym::i32, *sym::i64, *sym::isize];
    static ref INTS: [Symbol; 10] = [
        *sym::u8,
        *sym::u16,
        *sym::u32,
        *sym::u64,
        *sym::usize,
        *sym::i8,
        *sym::i16,
        *sym::i32,
        *sym::i64,
        *sym::isize
    ];
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

fn main() {
    println!("{}", order("is2 Thi1s T4est 3a"));
}

pub fn order( input: &str ) -> String {
// pub fn order( input: &str ) {

    let split = input.split(" ");
    let mut tokens = Vec::new();

    for s in split {
        tokens.push(s);
    }

    let nums = input.chars().filter_map(|a| a.to_digit(10)).collect::<Vec<_>>();

    if tokens.len() < 2 {
        return input.to_string()
    }

    if nums.len() != tokens.len() {
        println!("Rules of the game weren't followed!");
        return input.to_string()
    }

    // const val: usize = nums.len();
    let mut ordered = vec![String::new(); nums.len()];

    for idx in 0..nums.len() {
        let n: u32 = nums[idx] - 1;
        ordered[n as usize] = tokens[idx as usize].to_string();
    }

    let mut retval = String::new();

    for o in ordered {
        retval += &o;
        retval += " ";
    }

    let r = retval.trim();

    r.to_string()
}

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

    #[test]
    fn returns_expected() {
        assert_eq!(order("is2 Thi1s T4est 3a"), "Thi1s is2 3a T4est");
        assert_eq!(order(""), "");
    }

    // #[bench]
    // fn bench_order(b: &mut Bencher) {
    //     let bench_string = "fir6st at12 g11ood 5the someth13ing som3ething Suck1ing i4s 2at becom9ing 8to s10orta ste7p";
    //     let answer = "Suck1ing 2at som3ething i4s 5the fir6st ste7p 8to becom9ing s10orta g11ood at12 someth13ing";
    //     b.iter(|| {
    //         assert_eq!(order(bench_string), answer);
    //     });
    // }
}<commit_msg>updated source from kata<commit_after>#![feature(test)]
extern crate test;

fn main() {
    println!("{}", order("is2 Thi1s T4est 3a"));
}

pub fn order( input: &str ) -> String {
    let split = input.split(" ");
    let mut tokens = Vec::new();

    for s in split {
        tokens.push(s);
    }

    let nums = input.chars().filter_map(|a| a.to_digit(10)).collect::<Vec<_>>();

    if tokens.len() < 2 {
        return input.to_string()
    }

    if nums.len() != tokens.len() {
        println!("Rules of the game weren't followed!");
        return input.to_string()
    }

    // const val: usize = nums.len();
    let mut ordered = vec![String::new(); nums.len()];

    for idx in 0..nums.len() {
        let n: u32 = nums[idx] - 1;
        ordered[n as usize] = tokens[idx as usize].to_string();
    }

    let mut retval = String::new();

    for o in ordered {
        retval += &o;
        retval += " ";
    }

    let r = retval.trim();

    r.to_string()
}

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

    #[test]
    fn returns_expected() {
        assert_eq!(order("is2 Thi1s T4est 3a"), "Thi1s is2 3a T4est");
        assert_eq!(order(""), "");
    }

    // #[bench]
    // fn bench_order(b: &mut Bencher) {
    //     let bench_string = "fir6st at12 g11ood 5the someth13ing som3ething Suck1ing i4s 2at becom9ing 8to s10orta ste7p";
    //     let answer = "Suck1ing 2at som3ething i4s 5the fir6st ste7p 8to becom9ing s10orta g11ood at12 someth13ing";
    //     b.iter(|| {
    //         assert_eq!(order(bench_string), answer);
    //     });
    // }
}<|endoftext|>


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

//! Experimental extensions to `std` for Unix platforms.
//!
//! For now, this module is limited to extracting file descriptors,
//! but its functionality will grow over time.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//!     let f = File::create("foo.txt").unwrap();
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native unix bindings
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]

pub mod io;
pub mod ffi;
pub mod fs;
pub mod process;
pub mod raw;
pub mod thread;
pub mod net;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::DirEntryExt;
    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
    pub use super::fs::FileExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::thread::JoinHandleExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::process::{CommandExt, ExitStatusExt};
}
<commit_msg>Update doc comment for the Unix extension module<commit_after>// Copyright 2014 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.

//! Experimental extensions to `std` for Unix platforms.
//!
//! Provides access to platform-level information on Unix platforms, and
//! exposes Unix-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//!     let f = File::create("foo.txt").unwrap();
//!     let fd = f.as_raw_fd();
//!
//!     // use fd with native unix bindings
//! }
//! ```

#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]

pub mod io;
pub mod ffi;
pub mod fs;
pub mod process;
pub mod raw;
pub mod thread;
pub mod net;

/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::ffi::{OsStrExt, OsStringExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::fs::DirEntryExt;
    #[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
    pub use super::fs::FileExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::thread::JoinHandleExt;
    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::process::{CommandExt, ExitStatusExt};
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};

use attributes::Attribute;
use drawing_ctx::RsvgDrawingCtx;
use filter_context::RsvgFilterContext;
use error::AttributeError;
use filter_context::{FilterContext, RsvgFilterContext};
use handle::RsvgHandle;
use length::{LengthDir, RsvgLength};
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{parse, Parse};
use property_bag::PropertyBag;
use state::State;

mod ffi;
use self::ffi::*;

pub mod offset;

/// A filter primitive interface.
trait Filter: NodeTrait {
    /// Renders this filter primitive.
    ///
    /// If this filter primitive can't be rendered for whatever reason (for instance, a required
    /// property hasn't been provided), return without drawing anything.
    fn render(&self, ctx: *mut RsvgFilterContext);
}

/// The base filter node containing common properties.
struct Primitive {
    // The only purpose of this field is to communicate the render callback back to C code.
    // TODO: get rid of this once all filters have been ported to Rust.
    c_struct: RsvgFilterPrimitive,

    x: Cell<Option<RsvgLength>>,
    y: Cell<Option<RsvgLength>>,
    width: Cell<Option<RsvgLength>>,
    height: Cell<Option<RsvgLength>>,
    result: Cell<Option<String>>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum Input {
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterResult(String),
}

/// The base node for filter primitives which accept input.
struct PrimitiveWithInput {
    base: Primitive,
    in_: RefCell<Option<Input>>,
}

impl Primitive {
    /// Constructs a new `Primitive` with empty properties.
    #[inline]
    fn new<T: Filter>() -> Primitive {
        Primitive {
            c_struct: RsvgFilterPrimitive::new::<T>(),

            x: Cell::new(None),
            y: Cell::new(None),
            width: Cell::new(None),
            height: Cell::new(None),
            result: Cell::new(None),
        }
    }
}

impl NodeTrait for Primitive {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(Some(parse("x", value, LengthDir::Horizontal, None)?)),
                Attribute::Y => self.y.set(Some(parse("y", value, LengthDir::Vertical, None)?)),
                Attribute::Width => self.width.set(Some(parse("width", value, LengthDir::Horizontal, None)?)),
                Attribute::Height => self.height.set(Some(parse("height", value, LengthDir::Vertical, None)?)),
                Attribute::Result => self.result.set(Some(value.to_string())),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        // At least for now we have to return a *const RsvgFilterPrimitive.
        &self.c_struct as *const RsvgFilterPrimitive as *const RsvgCNodeImpl
    }
}

impl Parse for Input {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _data: Self::Data) -> Result<Self, Self::Err> {
        match s {
            "SourceGraphic" => Ok(Input::SourceGraphic),
            "SourceAlpha" => Ok(Input::SourceAlpha),
            "BackgroundImage" => Ok(Input::BackgroundImage),
            "BackgroundAlpha" => Ok(Input::BackgroundAlpha),
            "FillPaint" => Ok(Input::FillPaint),
            "StrokePaint" => Ok(Input::StrokePaint),
            s => Ok(Input::FilterResult(s.to_string())),
        }
    }
}

impl PrimitiveWithInput {
    /// Constructs a new `PrimitiveWithInput` with empty properties.
    #[inline]
    fn new<T: Filter>() -> PrimitiveWithInput {
        PrimitiveWithInput {
            base: Primitive::new(),
            in_: RefCell::new(None),
        }
    }
}

impl NodeTrait for PrimitiveWithInput {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::In => drop(self.in_.replace(Some(parse("in", value, (), None)?))),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}
<commit_msg>Add Deref from PrimitiveWithInput into Primitive<commit_after>use std::cell::{Cell, RefCell};
use std::ops::Deref;

use attributes::Attribute;
use drawing_ctx::RsvgDrawingCtx;
use filter_context::RsvgFilterContext;
use error::AttributeError;
use filter_context::{FilterContext, RsvgFilterContext};
use handle::RsvgHandle;
use length::{LengthDir, RsvgLength};
use node::{NodeResult, NodeTrait, RsvgCNodeImpl, RsvgNode};
use parsers::{parse, Parse};
use property_bag::PropertyBag;
use state::State;

mod ffi;
use self::ffi::*;

pub mod offset;

/// A filter primitive interface.
trait Filter: NodeTrait {
    /// Renders this filter primitive.
    ///
    /// If this filter primitive can't be rendered for whatever reason (for instance, a required
    /// property hasn't been provided), return without drawing anything.
    fn render(&self, ctx: *mut RsvgFilterContext);
}

/// The base filter node containing common properties.
struct Primitive {
    // The only purpose of this field is to communicate the render callback back to C code.
    // TODO: get rid of this once all filters have been ported to Rust.
    c_struct: RsvgFilterPrimitive,

    x: Cell<Option<RsvgLength>>,
    y: Cell<Option<RsvgLength>>,
    width: Cell<Option<RsvgLength>>,
    height: Cell<Option<RsvgLength>>,
    result: Cell<Option<String>>,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum Input {
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterResult(String),
}

/// The base node for filter primitives which accept input.
struct PrimitiveWithInput {
    base: Primitive,
    in_: RefCell<Option<Input>>,
}

impl Primitive {
    /// Constructs a new `Primitive` with empty properties.
    #[inline]
    fn new<T: Filter>() -> Primitive {
        Primitive {
            c_struct: RsvgFilterPrimitive::new::<T>(),

            x: Cell::new(None),
            y: Cell::new(None),
            width: Cell::new(None),
            height: Cell::new(None),
            result: Cell::new(None),
        }
    }
}

impl NodeTrait for Primitive {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(Some(parse("x", value, LengthDir::Horizontal, None)?)),
                Attribute::Y => self.y.set(Some(parse("y", value, LengthDir::Vertical, None)?)),
                Attribute::Width => self.width.set(Some(parse("width", value, LengthDir::Horizontal, None)?)),
                Attribute::Height => self.height.set(Some(parse("height", value, LengthDir::Vertical, None)?)),
                Attribute::Result => self.result.set(Some(value.to_string())),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        // At least for now we have to return a *const RsvgFilterPrimitive.
        &self.c_struct as *const RsvgFilterPrimitive as *const RsvgCNodeImpl
    }
}

impl Parse for Input {
    type Data = ();
    type Err = AttributeError;

    fn parse(s: &str, _data: Self::Data) -> Result<Self, Self::Err> {
        match s {
            "SourceGraphic" => Ok(Input::SourceGraphic),
            "SourceAlpha" => Ok(Input::SourceAlpha),
            "BackgroundImage" => Ok(Input::BackgroundImage),
            "BackgroundAlpha" => Ok(Input::BackgroundAlpha),
            "FillPaint" => Ok(Input::FillPaint),
            "StrokePaint" => Ok(Input::StrokePaint),
            s => Ok(Input::FilterResult(s.to_string())),
        }
    }
}

impl PrimitiveWithInput {
    /// Constructs a new `PrimitiveWithInput` with empty properties.
    #[inline]
    fn new<T: Filter>() -> PrimitiveWithInput {
        PrimitiveWithInput {
            base: Primitive::new(),
            in_: RefCell::new(None),
        }
    }
}

impl NodeTrait for PrimitiveWithInput {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::In => drop(self.in_.replace(Some(parse("in", value, (), None)?))),
                _ => (),
            }
        }

        Ok(())
    }

    #[inline]
    fn draw(&self, _: &RsvgNode, _: *mut RsvgDrawingCtx, _: &State, _: i32, _: bool) {
        // Nothing; filters are drawn in rsvg-cairo-draw.c.
    }

    #[inline]
    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        self.base.get_c_impl()
    }
}

impl Deref for PrimitiveWithInput {
    type Target = Primitive;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.base
    }
}
<|endoftext|>


<commit_before>use crate::Error;
use serde::{Deserialize, Serialize};

/// Specification of the linear memory of a module
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LinearMemorySpec<'a> {
    /// Specification of the heap used to implement the linear memory
    pub heap: HeapSpec,
    /// Initialization values for linear memory
    #[serde(borrow)]
    pub initializer: SparseData<'a>,
}

/// Specification of the linear memory of a module
///
/// This is a version of [`LinearMemorySpec`](../struct.LinearMemorySpec.html) with an
/// `OwnedSparseData` for the initializer.
/// This type is useful when directly building up a value to be serialized.
pub struct OwnedLinearMemorySpec {
    /// Specification of the heap used to implement the linear memory
    pub heap: HeapSpec,
    /// Initialization values for linear memory
    pub initializer: OwnedSparseData,
}

impl OwnedLinearMemorySpec {
    pub fn to_ref<'a>(&'a self) -> LinearMemorySpec<'a> {
        LinearMemorySpec {
            heap: self.heap.clone(),
            initializer: self.initializer.to_ref(),
        }
    }
}

/// Specifications about the heap of a Lucet module.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HeapSpec {
    /// Total bytes of memory for the heap to possibly expand into, as configured for Cranelift
    /// codegen.
    ///
    /// All of this memory is addressable. Only some part of it is accessible - from 0 to the
    /// initial size, guaranteed, and up to the `max_size`.  This size allows Cranelift to elide
    /// checks of the *base pointer*. At the moment that just means checking if it is greater than
    /// 4gb, in which case it can elide the base pointer check completely. In the future, Cranelift
    /// could use a solver to elide more base pointer checks if it can prove the calculation will
    /// always be less than this bound.
    ///
    /// Specified in bytes, and must be evenly divisible by the host page size (4K).
    pub reserved_size: u64,

    /// Total bytes of memory *after* the reserved area, as configured for Cranelift codegen.
    ///
    /// All of this memory is addressable, but it is never accessible - it is guaranteed to trap if
    /// an access happens in this region. This size allows Cranelift to use *common subexpression
    /// elimination* to reduce checks of the *sum of base pointer and offset* (where the offset is
    /// always rounded up to a multiple of the guard size, to be friendly to CSE).
    ///
    /// Specified in bytes, and must be evenly divisible by the host page size (4K).
    pub guard_size: u64,

    /// Total bytes of memory for the WebAssembly program's linear memory upon initialization.
    ///
    /// Specified in bytes, must be evenly divisible by the WebAssembly page size (64K), and must be
    /// less than or equal to `reserved_size`.
    pub initial_size: u64,

    /// Maximum bytes of memory for the WebAssembly program's linear memory at any time.
    ///
    /// This is not necessarily the same as `reserved_size` - we want to be able to tune the check
    /// bound there separately than the declaration of a max size in the client program.
    ///
    /// The program may optionally define this value. If it does, it must be less than the
    /// `reserved_size`. If it does not, the max size is left up to the runtime, and is allowed to
    /// be less than `reserved_size`.
    pub max_size: Option<u64>,
}

impl HeapSpec {
    pub fn new(
        reserved_size: u64,
        guard_size: u64,
        initial_size: u64,
        max_size: Option<u64>,
    ) -> Self {
        Self {
            reserved_size,
            guard_size,
            initial_size,
            max_size,
        }
    }

    /// Some very small test programs dont specify a memory import or definition.
    pub fn empty() -> Self {
        Self {
            reserved_size: 0,
            guard_size: 0,
            initial_size: 0,
            max_size: None,
        }
    }
}

/// A sparse representation of a Lucet module's initial heap.
///
/// The lifetime parameter exists to support zero-copy deserialization for the `&[u8]` slices
/// representing non-zero pages. For a variant with owned `Vec<u8>` pages, see
/// [`OwnedSparseData`](owned/struct.OwnedSparseData.html).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SparseData<'a> {
    /// Indices into the vector correspond to the offset, in host page (4k) increments, from the
    /// base of the instance heap.
    ///
    /// If the option at a given index is None, the page is initialized as zeros. Otherwise,
    /// the contents of the page are given as a slice of exactly 4k bytes.
    ///
    /// The deserializer of this datastructure does not make sure the 4k invariant holds,
    /// but the constructor on the serializier side does.
    #[serde(borrow)]
    pages: Vec<Option<&'a [u8]>>,
}

impl<'a> SparseData<'a> {
    /// Create a new `SparseData` from its constituent pages.
    ///
    /// Entries in the `pages` argument which are `Some` must contain a slice of exactly the host
    /// page size (4096), otherwise this function returns `Error::IncorrectPageSize`. Entries which
    /// are `None` are interpreted as empty pages, which will be zeroed by the runtime.
    pub fn new(pages: Vec<Option<&'a [u8]>>) -> Result<Self, Error> {
        if !pages.iter().all(|page| match page {
            Some(contents) => contents.len() == 4096,
            None => true,
        }) {
            return Err(Error::IncorrectPageSize);
        }

        Ok(Self { pages })
    }

    pub fn pages(&self) -> &[Option<&'a [u8]>] {
        &self.pages
    }

    pub fn get_page(&self, offset: usize) -> &Option<&'a [u8]> {
        self.pages.get(offset).unwrap_or(&None)
    }

    pub fn len(&self) -> usize {
        self.pages.len()
    }
}

/// A sparse representation of a Lucet module's initial heap.
///
/// This is a version of [`SparseData`](../struct.SparseData.html) with owned `Vec<u8>`s
/// representing pages. This type is useful when directly building up a value to be serialized.
pub struct OwnedSparseData {
    pages: Vec<Option<Vec<u8>>>,
}

impl OwnedSparseData {
    /// Create a new `OwnedSparseData` from its consitutent pages.
    ///
    /// Entries in the `pages` argument which are `Some` must contain a vector of exactly the host
    /// page size (4096), otherwise this function returns `Error::IncorrectPageSize`. Entries which
    /// are `None` are interpreted as empty pages, which will be zeroed by the runtime.
    pub fn new(pages: Vec<Option<Vec<u8>>>) -> Result<Self, Error> {
        if !pages.iter().all(|page| match page {
            Some(contents) => contents.len() == 4096,
            None => true,
        }) {
            return Err(Error::IncorrectPageSize);
        }
        Ok(Self { pages })
    }

    /// Create a [`SparseData`](../struct.SparseData.html) backed by the values in this
    /// `OwnedSparseData`.
    pub fn to_ref<'a>(&'a self) -> SparseData<'a> {
        SparseData::new(
            self.pages
                .iter()
                .map(|c| match c {
                    Some(data) => Some(data.as_slice()),
                    None => None,
                })
                .collect(),
        )
        .expect("SparseData invariant enforced by OwnedSparseData constructor")
    }
}
<commit_msg>Delete incorrect assumption about the max_size in a HeapSpec. (#467)<commit_after>use crate::Error;
use serde::{Deserialize, Serialize};

/// Specification of the linear memory of a module
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LinearMemorySpec<'a> {
    /// Specification of the heap used to implement the linear memory
    pub heap: HeapSpec,
    /// Initialization values for linear memory
    #[serde(borrow)]
    pub initializer: SparseData<'a>,
}

/// Specification of the linear memory of a module
///
/// This is a version of [`LinearMemorySpec`](../struct.LinearMemorySpec.html) with an
/// `OwnedSparseData` for the initializer.
/// This type is useful when directly building up a value to be serialized.
pub struct OwnedLinearMemorySpec {
    /// Specification of the heap used to implement the linear memory
    pub heap: HeapSpec,
    /// Initialization values for linear memory
    pub initializer: OwnedSparseData,
}

impl OwnedLinearMemorySpec {
    pub fn to_ref<'a>(&'a self) -> LinearMemorySpec<'a> {
        LinearMemorySpec {
            heap: self.heap.clone(),
            initializer: self.initializer.to_ref(),
        }
    }
}

/// Specifications about the heap of a Lucet module.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HeapSpec {
    /// Total bytes of memory for the heap to possibly expand into, as configured for Cranelift
    /// codegen.
    ///
    /// All of this memory is addressable. Only some part of it is accessible - from 0 to the
    /// initial size, guaranteed, and up to the `max_size`.  This size allows Cranelift to elide
    /// checks of the *base pointer*. At the moment that just means checking if it is greater than
    /// 4gb, in which case it can elide the base pointer check completely. In the future, Cranelift
    /// could use a solver to elide more base pointer checks if it can prove the calculation will
    /// always be less than this bound.
    ///
    /// Specified in bytes, and must be evenly divisible by the host page size (4K).
    pub reserved_size: u64,

    /// Total bytes of memory *after* the reserved area, as configured for Cranelift codegen.
    ///
    /// All of this memory is addressable, but it is never accessible - it is guaranteed to trap if
    /// an access happens in this region. This size allows Cranelift to use *common subexpression
    /// elimination* to reduce checks of the *sum of base pointer and offset* (where the offset is
    /// always rounded up to a multiple of the guard size, to be friendly to CSE).
    ///
    /// Specified in bytes, and must be evenly divisible by the host page size (4K).
    pub guard_size: u64,

    /// Total bytes of memory for the WebAssembly program's linear memory upon initialization.
    ///
    /// Specified in bytes, must be evenly divisible by the WebAssembly page size (64K), and must be
    /// less than or equal to `reserved_size`.
    pub initial_size: u64,

    /// Maximum bytes of memory for the WebAssembly program's linear memory at any time.
    ///
    /// This is not necessarily the same as `reserved_size` - we want to be able to tune the check
    /// bound there separately than the declaration of a max size in the client program.
    ///
    /// The program may optionally define this value. If it does not, the max size is left up to
    /// the runtime, and is allowed to be less than `reserved_size`.
    pub max_size: Option<u64>,
}

impl HeapSpec {
    pub fn new(
        reserved_size: u64,
        guard_size: u64,
        initial_size: u64,
        max_size: Option<u64>,
    ) -> Self {
        Self {
            reserved_size,
            guard_size,
            initial_size,
            max_size,
        }
    }

    /// Some very small test programs dont specify a memory import or definition.
    pub fn empty() -> Self {
        Self {
            reserved_size: 0,
            guard_size: 0,
            initial_size: 0,
            max_size: None,
        }
    }
}

/// A sparse representation of a Lucet module's initial heap.
///
/// The lifetime parameter exists to support zero-copy deserialization for the `&[u8]` slices
/// representing non-zero pages. For a variant with owned `Vec<u8>` pages, see
/// [`OwnedSparseData`](owned/struct.OwnedSparseData.html).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SparseData<'a> {
    /// Indices into the vector correspond to the offset, in host page (4k) increments, from the
    /// base of the instance heap.
    ///
    /// If the option at a given index is None, the page is initialized as zeros. Otherwise,
    /// the contents of the page are given as a slice of exactly 4k bytes.
    ///
    /// The deserializer of this datastructure does not make sure the 4k invariant holds,
    /// but the constructor on the serializier side does.
    #[serde(borrow)]
    pages: Vec<Option<&'a [u8]>>,
}

impl<'a> SparseData<'a> {
    /// Create a new `SparseData` from its constituent pages.
    ///
    /// Entries in the `pages` argument which are `Some` must contain a slice of exactly the host
    /// page size (4096), otherwise this function returns `Error::IncorrectPageSize`. Entries which
    /// are `None` are interpreted as empty pages, which will be zeroed by the runtime.
    pub fn new(pages: Vec<Option<&'a [u8]>>) -> Result<Self, Error> {
        if !pages.iter().all(|page| match page {
            Some(contents) => contents.len() == 4096,
            None => true,
        }) {
            return Err(Error::IncorrectPageSize);
        }

        Ok(Self { pages })
    }

    pub fn pages(&self) -> &[Option<&'a [u8]>] {
        &self.pages
    }

    pub fn get_page(&self, offset: usize) -> &Option<&'a [u8]> {
        self.pages.get(offset).unwrap_or(&None)
    }

    pub fn len(&self) -> usize {
        self.pages.len()
    }
}

/// A sparse representation of a Lucet module's initial heap.
///
/// This is a version of [`SparseData`](../struct.SparseData.html) with owned `Vec<u8>`s
/// representing pages. This type is useful when directly building up a value to be serialized.
pub struct OwnedSparseData {
    pages: Vec<Option<Vec<u8>>>,
}

impl OwnedSparseData {
    /// Create a new `OwnedSparseData` from its consitutent pages.
    ///
    /// Entries in the `pages` argument which are `Some` must contain a vector of exactly the host
    /// page size (4096), otherwise this function returns `Error::IncorrectPageSize`. Entries which
    /// are `None` are interpreted as empty pages, which will be zeroed by the runtime.
    pub fn new(pages: Vec<Option<Vec<u8>>>) -> Result<Self, Error> {
        if !pages.iter().all(|page| match page {
            Some(contents) => contents.len() == 4096,
            None => true,
        }) {
            return Err(Error::IncorrectPageSize);
        }
        Ok(Self { pages })
    }

    /// Create a [`SparseData`](../struct.SparseData.html) backed by the values in this
    /// `OwnedSparseData`.
    pub fn to_ref<'a>(&'a self) -> SparseData<'a> {
        SparseData::new(
            self.pages
                .iter()
                .map(|c| match c {
                    Some(data) => Some(data.as_slice()),
                    None => None,
                })
                .collect(),
        )
        .expect("SparseData invariant enforced by OwnedSparseData constructor")
    }
}
<|endoftext|>