<commit_before>//! Types which represent various database backends

use byteorder::ByteOrder;

use query_builder::bind_collector::BindCollector;
use query_builder::QueryBuilder;
use sql_types::{self, HasSqlType};

/// A database backend
///
/// This trait represents the concept of a backend (e.g. "MySQL" vs "SQLite").
/// It is separate from a [`Connection`](../connection/trait.Connection.html)
/// to that backend.
/// One backend may have multiple concrete connection implementations.
///
/// Implementations of this trait should not assume details about how the
/// connection is implemented.
/// For example, the `Pg` backend does not assume that `libpq` is being used.
/// Implementations of this trait can and should care about details of the wire
/// protocol used to communicated with the database.
pub trait Backend
where
    Self: Sized,
    Self: HasSqlType<sql_types::SmallInt>,
    Self: HasSqlType<sql_types::Integer>,
    Self: HasSqlType<sql_types::BigInt>,
    Self: HasSqlType<sql_types::Float>,
    Self: HasSqlType<sql_types::Double>,
    Self: HasSqlType<sql_types::VarChar>,
    Self: HasSqlType<sql_types::Text>,
    Self: HasSqlType<sql_types::Binary>,
    Self: HasSqlType<sql_types::Date>,
    Self: HasSqlType<sql_types::Time>,
    Self: HasSqlType<sql_types::Timestamp>,
    Self: for<'a> HasRawValue<'a>,
{
    /// The concrete `QueryBuilder` implementation for this backend.
    type QueryBuilder: QueryBuilder<Self>;
    /// The concrete `BindCollector` implementation for this backend.
    ///
    /// Most backends should use [`RawBytesBindCollector`].
    ///
    /// [`RawBytesBindCollector`]: ../query_builder/bind_collector/struct.RawBytesBindCollector.html
    type BindCollector: BindCollector<Self>;
    /// What byte order is used to transmit integers?
    ///
    /// This type is only used if `RawValue` is `[u8]`.
    type ByteOrder: ByteOrder;
}

/// The raw representation of a database value given to `FromSql`.
///
/// This trait is separate from `Backend` to imitate `type RawValue<'a>`. It
/// should only be referenced directly by implementors. Users of this type
/// should instead use the [`RawValue`] helper type instead.
pub trait HasRawValue<'a> {
    /// The actual type given to `FromSql`, with lifetimes applied. This type
    /// should not be used directly. Use the [`RawValue`] helper type instead.
    type RawValue;
}

/// A helper type to get the raw representation of a database type given to
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;

/// Does this backend support `RETURNING` clauses?
pub trait SupportsReturningClause {}
/// Does this backend support the bare `DEFAULT` keyword?
pub trait SupportsDefaultKeyword {}
/// Does this backend use the standard `SAVEPOINT` syntax?
pub trait UsesAnsiSavepointSyntax {}

#[cfg(feature = "with-deprecated")]
#[deprecated(since = "1.1.0", note = "use `sql_types::TypeMetadata` instead")]
pub use sql_types::TypeMetadata;
<commit_msg>Fix doc links<commit_after>//! Types which represent various database backends

use byteorder::ByteOrder;

use query_builder::bind_collector::BindCollector;
use query_builder::QueryBuilder;
use sql_types::{self, HasSqlType};

/// A database backend
///
/// This trait represents the concept of a backend (e.g. "MySQL" vs "SQLite").
/// It is separate from a [`Connection`](../connection/trait.Connection.html)
/// to that backend.
/// One backend may have multiple concrete connection implementations.
///
/// Implementations of this trait should not assume details about how the
/// connection is implemented.
/// For example, the `Pg` backend does not assume that `libpq` is being used.
/// Implementations of this trait can and should care about details of the wire
/// protocol used to communicated with the database.
pub trait Backend
where
    Self: Sized,
    Self: HasSqlType<sql_types::SmallInt>,
    Self: HasSqlType<sql_types::Integer>,
    Self: HasSqlType<sql_types::BigInt>,
    Self: HasSqlType<sql_types::Float>,
    Self: HasSqlType<sql_types::Double>,
    Self: HasSqlType<sql_types::VarChar>,
    Self: HasSqlType<sql_types::Text>,
    Self: HasSqlType<sql_types::Binary>,
    Self: HasSqlType<sql_types::Date>,
    Self: HasSqlType<sql_types::Time>,
    Self: HasSqlType<sql_types::Timestamp>,
    Self: for<'a> HasRawValue<'a>,
{
    /// The concrete `QueryBuilder` implementation for this backend.
    type QueryBuilder: QueryBuilder<Self>;
    /// The concrete `BindCollector` implementation for this backend.
    ///
    /// Most backends should use [`RawBytesBindCollector`].
    ///
    /// [`RawBytesBindCollector`]: ../query_builder/bind_collector/struct.RawBytesBindCollector.html
    type BindCollector: BindCollector<Self>;
    /// What byte order is used to transmit integers?
    ///
    /// This type is only used if `RawValue` is `[u8]`.
    type ByteOrder: ByteOrder;
}

/// The raw representation of a database value given to `FromSql`.
///
/// This trait is separate from `Backend` to imitate `type RawValue<'a>`. It
/// should only be referenced directly by implementors. Users of this type
/// should instead use the [`RawValue`](type.RawValue.html) helper type instead.
pub trait HasRawValue<'a> {
    /// The actual type given to `FromSql`, with lifetimes applied. This type
    /// should not be used directly. Use the [`RawValue`](type.RawValue.html)
    /// helper type instead.
    type RawValue;
}

/// A helper type to get the raw representation of a database type given to
/// `FromSql`. Equivalent to `<DB as Backend>::RawValue<'a>`.
pub type RawValue<'a, DB> = <DB as HasRawValue<'a>>::RawValue;

/// Does this backend support `RETURNING` clauses?
pub trait SupportsReturningClause {}
/// Does this backend support the bare `DEFAULT` keyword?
pub trait SupportsDefaultKeyword {}
/// Does this backend use the standard `SAVEPOINT` syntax?
pub trait UsesAnsiSavepointSyntax {}

#[cfg(feature = "with-deprecated")]
#[deprecated(since = "1.1.0", note = "use `sql_types::TypeMetadata` instead")]
pub use sql_types::TypeMetadata;
<|endoftext|>


<commit_before>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use rustc::middle::def::Def::{DefVariant, DefStruct};

use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init { check_expr(cx, o, bindings) }
        check_pat(cx, pat, init, span, bindings);
    }
}

fn is_binding(cx: &Context, pat: &Pat) -> bool {
    match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
        Some(DefVariant(..)) | Some(DefStruct(..)) => false,
        _ => true
    }
}

fn check_pat<T>(cx: &Context, pat: &Pat, init: &Option<T>, span: Span,
        bindings: &mut Vec<Name>) where T: Deref<Target=Expr> {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if is_binding(cx, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                } else {
                    bindings.push(name);
                }
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        //PatQPath(QSelf, Path),
        //PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
        //PatTup(Vec<P<Pat>>),
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                match initp.node {
                    ExprBox(_, ref inner_init) =>
                        check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                    //TODO: ExprCall on Box::new
                    _ => check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        //PatRegion(P<Pat>, Mutability),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            let len = bindings.len();
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
                bindings.truncate(len);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<commit_msg>extended pattern matching<commit_after>use std::ops::Deref;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::visit::FnKind;

use rustc::lint::{Context, LintArray, LintPass};
use rustc::middle::def::Def::{DefVariant, DefStruct};

use utils::{in_external_macro, snippet, span_lint};

declare_lint!(pub SHADOW_SAME, Allow,
    "rebinding a name to itself, e.g. `let mut x = &mut x`");
declare_lint!(pub SHADOW_REUSE, Allow,
    "rebinding a name to an expression that re-uses the original value, e.g. \
    `let x = x + 1`");
declare_lint!(pub SHADOW_UNRELATED, Warn,
    "The name is re-bound without even using the original value");

#[derive(Copy, Clone)]
pub struct ShadowPass;

impl LintPass for ShadowPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl,
            block: &Block, _: Span, _: NodeId) {
        if in_external_macro(cx, block.span) { return; }
        check_fn(cx, decl, block);
    }
}

fn check_fn(cx: &Context, decl: &FnDecl, block: &Block) {
    let mut bindings = Vec::new();
    for arg in &decl.inputs {
        if let PatIdent(_, ident, _) = arg.pat.node {
            bindings.push(ident.node.name)
        }
    }
    check_block(cx, block, &mut bindings);
}

fn check_block(cx: &Context, block: &Block, bindings: &mut Vec<Name>) {
    let len = bindings.len();
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) => check_decl(cx, decl, bindings),
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                check_expr(cx, e, bindings),
            _ => ()
        }
    }
    if let Some(ref o) = block.expr { check_expr(cx, o, bindings); }
    bindings.truncate(len);
}

fn check_decl(cx: &Context, decl: &Decl, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, decl.span) { return; }
    if let DeclLocal(ref local) = decl.node {
        let Local{ ref pat, ref ty, ref init, id: _, span } = **local;
        if let &Some(ref t) = ty { check_ty(cx, t, bindings) }
        if let &Some(ref o) = init {
            check_expr(cx, o, bindings);
            check_pat(cx, pat, &Some(o), span, bindings);
        } else {
            check_pat(cx, pat, &None, span, bindings);
        }
    }
}

fn is_binding(cx: &Context, pat: &Pat) -> bool {
    match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
        Some(DefVariant(..)) | Some(DefStruct(..)) => false,
        _ => true
    }
}

fn check_pat(cx: &Context, pat: &Pat, init: &Option<&Expr>, span: Span,
        bindings: &mut Vec<Name>) {
    //TODO: match more stuff / destructuring
    match pat.node {
        PatIdent(_, ref ident, ref inner) => {
            let name = ident.node.name;
            if is_binding(cx, pat) {
                if bindings.contains(&name) {
                    lint_shadow(cx, name, span, pat.span, init);
                } else {
                    bindings.push(name);
                }
            }
            if let Some(ref p) = *inner { check_pat(cx, p, init, span, bindings); }
        },
        //PatEnum(Path, Option<Vec<P<Pat>>>),
        PatStruct(_, ref pfields, _) =>
            if let Some(ref init_struct) = *init { // TODO follow
                if let ExprStruct(_, ref efields, ref _base) = init_struct.node {
                    // TODO: follow base
                    for field in pfields {
                        let ident = field.node.ident;
                        let efield = efields.iter()
                            .find(|ref f| f.ident.node == ident)
                            .map(|f| &*f.expr);
                        check_pat(cx, &field.node.pat, &efield, span, bindings);
                    }
                } else {
                    for field in pfields {
                        check_pat(cx, &field.node.pat, &None, span, bindings);
                    }
                }
            } else {
                for field in pfields {
                    check_pat(cx, &field.node.pat, &None, span, bindings);
                }
            },
        PatTup(ref inner) =>
            if let Some(ref init_tup) = *init { //TODO: follow
                if let ExprTup(ref tup) = init_tup.node {
                    for (i, p) in inner.iter().enumerate() {
                        check_pat(cx, p, &Some(&tup[i]), p.span, bindings);
                    }
                } else {
                    for p in inner {
                        check_pat(cx, p, &None, span, bindings);
                    }
                }
            } else {
                for p in inner {
                    check_pat(cx, p, &None, span, bindings);
                }
            },
        PatBox(ref inner) => {
            if let Some(ref initp) = *init {
                match initp.node {
                    ExprBox(_, ref inner_init) =>
                        check_pat(cx, inner, &Some(&**inner_init), span, bindings),
                    //TODO: ExprCall on Box::new
                    _ => check_pat(cx, inner, init, span, bindings),
                }
            } else {
                check_pat(cx, inner, init, span, bindings);
            }
        },
        //PatRegion(P<Pat>, Mutability),
        //PatRange(P<Expr>, P<Expr>),
        //PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
        _ => (),
    }
}

fn lint_shadow<T>(cx: &Context, name: Name, span: Span, lspan: Span, init:
        &Option<T>) where T: Deref<Target=Expr> {
    if let &Some(ref expr) = init {
        if is_self_shadow(name, expr) {
            span_lint(cx, SHADOW_SAME, span, &format!(
                "{} is shadowed by itself in {}",
                snippet(cx, lspan, "_"),
                snippet(cx, expr.span, "..")));
        } else {
            if contains_self(name, expr) {
                span_lint(cx, SHADOW_REUSE, span, &format!(
                    "{} is shadowed by {} which reuses the original value",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            } else {
                span_lint(cx, SHADOW_UNRELATED, span, &format!(
                    "{} is shadowed by {} in this declaration",
                    snippet(cx, lspan, "_"),
                    snippet(cx, expr.span, "..")));
            }
        }
    } else {
        span_lint(cx, SHADOW_UNRELATED, span, &format!(
            "{} is shadowed in this declaration", snippet(cx, lspan, "_")));
    }
}

fn check_expr(cx: &Context, expr: &Expr, bindings: &mut Vec<Name>) {
    if in_external_macro(cx, expr.span) { return; }
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(None, ref e)
            => { check_expr(cx, e, bindings) },
        ExprBox(Some(ref place), ref e) => {
            check_expr(cx, place, bindings); check_expr(cx, e, bindings) }
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            { check_block(cx, block, bindings) },
        //ExprCall
        //ExprMethodCall
        ExprVec(ref v) | ExprTup(ref v) =>
            for ref e in v { check_expr(cx, e, bindings) },
        ExprIf(ref cond, ref then, ref otherwise) => {
            check_expr(cx, cond, bindings);
            check_block(cx, then, bindings);
            if let &Some(ref o) = otherwise { check_expr(cx, o, bindings); }
        },
        ExprWhile(ref cond, ref block, _) => {
            check_expr(cx, cond, bindings);
            check_block(cx, block, bindings);
        },
        ExprMatch(ref init, ref arms, _) => {
            check_expr(cx, init, bindings);
            let len = bindings.len();
            for ref arm in arms {
                for ref pat in &arm.pats {
                    check_pat(cx, &pat, &Some(&**init), pat.span, bindings);
                    //TODO: This is ugly, but needed to get the right type
                }
                if let Some(ref guard) = arm.guard {
                    check_expr(cx, guard, bindings);
                }
                check_expr(cx, &arm.body, bindings);
                bindings.truncate(len);
            }
        },
        _ => ()
    }
}

fn check_ty(cx: &Context, ty: &Ty, bindings: &mut Vec<Name>) {
    match ty.node {
        TyParen(ref sty) | TyObjectSum(ref sty, _) |
        TyVec(ref sty) => check_ty(cx, sty, bindings),
        TyFixedLengthVec(ref fty, ref expr) => {
            check_ty(cx, fty, bindings);
            check_expr(cx, expr, bindings);
        },
        TyPtr(MutTy{ ty: ref mty, .. }) |
        TyRptr(_, MutTy{ ty: ref mty, .. }) => check_ty(cx, mty, bindings),
        TyTup(ref tup) => { for ref t in tup { check_ty(cx, t, bindings) } },
        TyTypeof(ref expr) => check_expr(cx, expr, bindings),
        _ => (),
    }
}

fn is_self_shadow(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprBox(_, ref inner) |
        ExprParen(ref inner) |
        ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
        ExprBlock(ref block) => block.stmts.is_empty() && block.expr.as_ref().
            map_or(false, |ref e| is_self_shadow(name, e)),
        ExprUnary(op, ref inner) => (UnUniq == op || UnDeref == op) &&
            is_self_shadow(name, inner),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false,
    }
}

fn path_eq_name(name: Name, path: &Path) -> bool {
    !path.global && path.segments.len() == 1 &&
        path.segments[0].identifier.name == name
}

fn contains_self(name: Name, expr: &Expr) -> bool {
    match expr.node {
        ExprUnary(_, ref e) | ExprParen(ref e) | ExprField(ref e, _) |
        ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | ExprBox(_, ref e)
            => contains_self(name, e),
        ExprBinary(_, ref l, ref r) =>
            contains_self(name, l) || contains_self(name, r),
        ExprBlock(ref block) | ExprLoop(ref block, _) =>
            contains_block_self(name, block),
        ExprCall(ref fun, ref args) => contains_self(name, fun) ||
            args.iter().any(|ref a| contains_self(name, a)),
        ExprMethodCall(_, _, ref args) =>
            args.iter().any(|ref a| contains_self(name, a)),
        ExprVec(ref v) | ExprTup(ref v) =>
            v.iter().any(|ref e| contains_self(name, e)),
        ExprIf(ref cond, ref then, ref otherwise) =>
            contains_self(name, cond) || contains_block_self(name, then) ||
            otherwise.as_ref().map_or(false, |ref e| contains_self(name, e)),
        ExprWhile(ref e, ref block, _)  =>
            contains_self(name, e) || contains_block_self(name, block),
        ExprMatch(ref e, ref arms, _) =>
            arms.iter().any(|ref arm| arm.pats.iter().any(|ref pat|
                contains_pat_self(name, pat))) || contains_self(name, e),
        ExprPath(_, ref path) => path_eq_name(name, path),
        _ => false
    }
}

fn contains_block_self(name: Name, block: &Block) -> bool {
    for stmt in &block.stmts {
        match stmt.node {
            StmtDecl(ref decl, _) =>
            if let DeclLocal(ref local) = decl.node {
                //TODO: We don't currently handle the case where the name
                //is shadowed wiithin the block; this means code including this
                //degenerate pattern will get the wrong warning.
                if let Some(ref init) = local.init {
                    if contains_self(name, init) { return true; }
                }
            },
            StmtExpr(ref e, _) | StmtSemi(ref e, _) =>
                if contains_self(name, e) { return true },
            _ => ()
        }
    }
    if let Some(ref e) = block.expr { contains_self(name, e) } else { false }
}

fn contains_pat_self(name: Name, pat: &Pat) -> bool {
    match pat.node {
        PatIdent(_, ref ident, ref inner) => name == ident.node.name ||
            inner.as_ref().map_or(false, |ref p| contains_pat_self(name, p)),
        PatEnum(_, ref opats) => opats.as_ref().map_or(false,
            |pats| pats.iter().any(|p| contains_pat_self(name, p))),
        PatQPath(_, ref path) => path_eq_name(name, path),
        PatStruct(_, ref fieldpats, _) => fieldpats.iter().any(
            |ref fp| contains_pat_self(name, &fp.node.pat)),
        PatTup(ref ps) => ps.iter().any(|ref p| contains_pat_self(name, p)),
        PatBox(ref p) |
        PatRegion(ref p, _) => contains_pat_self(name, p),
        PatRange(ref from, ref until) =>
            contains_self(name, from) || contains_self(name, until),
        PatVec(ref pre, ref opt, ref post) =>
            pre.iter().any(|ref p| contains_pat_self(name, p)) ||
                opt.as_ref().map_or(false, |ref p| contains_pat_self(name, p)) ||
                post.iter().any(|ref p| contains_pat_self(name, p)),
        _ => false,
    }
}
<|endoftext|>


<commit_before>//! Define trait for Hermite matrices

use ndarray::{Ix2, Array, LinalgScalar};
use std::fmt::Debug;
use num_traits::float::Float;

use matrix::Matrix;
use error::{LinalgError, NotSquareError};
use qr::ImplQR;
use svd::ImplSVD;
use norm::ImplNorm;
use solve::ImplSolve;

/// Methods for square matrices
///
/// This trait defines method for square matrices,
/// but does not assure that the matrix is square.
/// If not square, `NotSquareError` will be thrown.
pub trait SquareMatrix: Matrix {
    // fn eig(self) -> (Self::Vector, Self);
    /// inverse matrix
    fn inv(self) -> Result<Self, LinalgError>;
    /// trace of matrix
    fn trace(&self) -> Result<Self::Scalar, LinalgError>;
    /// test matrix is square
    fn check_square(&self) -> Result<(), NotSquareError> {
        let (rows, cols) = self.size();
        if rows == cols {
            Ok(())
        } else {
            Err(NotSquareError {
                rows: rows,
                cols: cols,
            })
        }
    }
}

impl<A> SquareMatrix for Array<A, Ix2>
    where A: ImplQR + ImplNorm + ImplSVD + ImplSolve + LinalgScalar + Float + Debug
{
    fn inv(self) -> Result<Self, LinalgError> {
        try!(self.check_square());
        let (n, _) = self.size();
        let is_fortran_align = self.strides()[0] > self.strides()[1];
        let a = ImplSolve::inv(self.layout()?, n, self.into_raw_vec())?;
        let m = Array::from_vec(a).into_shape((n, n)).unwrap();
        if is_fortran_align {
            Ok(m)
        } else {
            Ok(m.reversed_axes())
        }
    }
    fn trace(&self) -> Result<Self::Scalar, LinalgError> {
        try!(self.check_square());
        let (n, _) = self.size();
        Ok((0..n).fold(A::zero(), |sum, i| sum + self[(i, i)]))
    }
}
<commit_msg>Small rev for layout<commit_after>//! Define trait for Hermite matrices

use ndarray::{Ix2, Array, LinalgScalar};
use std::fmt::Debug;
use num_traits::float::Float;
use lapack::c::Layout;

use matrix::Matrix;
use error::{LinalgError, NotSquareError};
use qr::ImplQR;
use svd::ImplSVD;
use norm::ImplNorm;
use solve::ImplSolve;

/// Methods for square matrices
///
/// This trait defines method for square matrices,
/// but does not assure that the matrix is square.
/// If not square, `NotSquareError` will be thrown.
pub trait SquareMatrix: Matrix {
    // fn eig(self) -> (Self::Vector, Self);
    /// inverse matrix
    fn inv(self) -> Result<Self, LinalgError>;
    /// trace of matrix
    fn trace(&self) -> Result<Self::Scalar, LinalgError>;
    /// test matrix is square
    fn check_square(&self) -> Result<(), NotSquareError> {
        let (rows, cols) = self.size();
        if rows == cols {
            Ok(())
        } else {
            Err(NotSquareError {
                rows: rows,
                cols: cols,
            })
        }
    }
}

impl<A> SquareMatrix for Array<A, Ix2>
    where A: ImplQR + ImplNorm + ImplSVD + ImplSolve + LinalgScalar + Float + Debug
{
    fn inv(self) -> Result<Self, LinalgError> {
        try!(self.check_square());
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = ImplSolve::inv(layout, n, self.into_raw_vec())?;
        let m = Array::from_vec(a).into_shape((n, n)).unwrap();
        match layout {
            Layout::RowMajor => Ok(m),
            Layout::ColumnMajor => Ok(m.reversed_axes()),
        }
    }
    fn trace(&self) -> Result<Self::Scalar, LinalgError> {
        try!(self.check_square());
        let (n, _) = self.size();
        Ok((0..n).fold(A::zero(), |sum, i| sum + self[(i, i)]))
    }
}
<|endoftext|>


<commit_before>use codec::CodecTrait;
use codec_pandoc::{decode_pandoc, encode_node, PandocCodec};
use test_props::{article, proptest::prelude::*, Freedom};
use test_utils::assert_json_eq;

proptest! {
    #![proptest_config(ProptestConfig::with_cases(100))]

    #[test]
    fn test(input in article(
        Freedom::Min,
        PandocCodec::spec().unsupported_types,
        PandocCodec::spec().unsupported_properties,
    )) {
        let pandoc = encode_node(&input).unwrap();
        let output = decode_pandoc(pandoc).unwrap();
        assert_json_eq!(input, output);
    }
}
<commit_msg>test(Pandoc codec): Use default number of tests<commit_after>use codec::CodecTrait;
use codec_pandoc::{decode_pandoc, encode_node, PandocCodec};
use test_props::{article, proptest::prelude::*, Freedom};
use test_utils::assert_json_eq;

proptest! {
    #[test]
    fn test(input in article(
        Freedom::Min,
        PandocCodec::spec().unsupported_types,
        PandocCodec::spec().unsupported_properties,
    )) {
        let pandoc = encode_node(&input).unwrap();
        let output = decode_pandoc(pandoc).unwrap();
        assert_json_eq!(input, output);
    }
}
<|endoftext|>


<commit_before>use mio::*;
use std::cell::RefCell;
use std::io;
use std::rc::Rc;
use std::time::Duration;
use slab::Slab;

pub trait EventHandler {
    fn on_ready(&mut self, selector: &mut Selector, event: Event);
}

impl<F> EventHandler for F where F: FnMut(&mut Selector, Event) {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self(selector, event);
    }
}

// for convenience
impl<T: EventHandler> EventHandler for Rc<RefCell<T>> {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self.borrow_mut().on_ready(selector, event);
    }
}

pub struct Selector {
    poll: Poll,
    handlers: Slab<Rc<RefCell<Box<EventHandler>>>, Token>,
}

impl Selector {
    pub fn new() -> io::Result<Self> {
        Ok(Self {
            poll: Poll::new()?,
            handlers: Slab::with_capacity(1024),
        })
    }

    pub fn register<E>(&mut self, handle: &E, handler: Box<EventHandler>,
                   interest: Ready, opts: PollOpt) -> io::Result<Token>
            where E: Evented + ?Sized {
        let token = self.handlers.insert(Rc::new(RefCell::new(handler)))
                        .map_err(|_| io::Error::new(io::ErrorKind::Other, "Cannot allocate slab slot"))?;
        self.poll.register(handle, token, interest, opts)?;
        Ok(token)
    }

    pub fn reregister<E>(&mut self, handle: &E, token: Token,
                   interest: Ready, opts: PollOpt) -> io::Result<()>
            where E: Evented + ?Sized {
        self.poll.reregister(handle, token, interest, opts)
    }

    pub fn deregister<E>(&mut self, handle: &E, token: Token) -> io::Result<()>
            where E: Evented + ?Sized {
        self.handlers.remove(token).expect("Unknown token removed");
        self.poll.deregister(handle)
    }

    pub fn poll(&mut self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(events, timeout)
    }

    pub fn run_handler(&mut self, event: Event) {
        let handler = self.handlers.get_mut(event.token()).expect("Token not found").clone();
        handler.borrow_mut().on_ready(self, event);
    }
}
<commit_msg>Make Selector accept an empty Ready<commit_after>use mio::*;
use std::cell::RefCell;
use std::io;
use std::rc::Rc;
use std::time::Duration;
use slab::Slab;

pub trait EventHandler {
    fn on_ready(&mut self, selector: &mut Selector, event: Event);
}

impl<F> EventHandler for F where F: FnMut(&mut Selector, Event) {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self(selector, event);
    }
}

// for convenience
impl<T: EventHandler> EventHandler for Rc<RefCell<T>> {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self.borrow_mut().on_ready(selector, event);
    }
}

pub struct Selector {
    poll: Poll,
    handlers: Slab<SelectionHandler, Token>,
}

struct SelectionHandler {
    handler: Rc<RefCell<Box<EventHandler>>>,
    registered: bool,
}

impl SelectionHandler {
    fn new(handler: Box<EventHandler>) -> Self {
        Self {
            handler: Rc::new(RefCell::new(handler)),
            registered: true,
        }
    }
}

impl Selector {
    pub fn new() -> io::Result<Self> {
        Ok(Self {
            poll: Poll::new()?,
            handlers: Slab::with_capacity(1024),
        })
    }

    pub fn register<E>(&mut self, handle: &E, handler: Box<EventHandler>,
                   interest: Ready, opts: PollOpt) -> io::Result<Token>
            where E: Evented + ?Sized {
        let token = self.handlers.insert(SelectionHandler::new(handler))
                        .map_err(|_| io::Error::new(io::ErrorKind::Other, "Cannot allocate slab slot"))?;
        self.poll.register(handle, token, interest, opts)?;
        Ok(token)
    }

    pub fn reregister<E>(&mut self, handle: &E, token: Token,
                   interest: Ready, opts: PollOpt) -> io::Result<()>
            where E: Evented + ?Sized {
        // a Poll does not accept to register an empty Ready
        // for simplifying its usage, expose an API that does
        let selection_handler = self.handlers.get_mut(token).expect("Token not found");
        if interest.is_empty() {
            if selection_handler.registered {
                selection_handler.registered = false;
                self.poll.deregister(handle)?;
            }
            Ok(())
        } else {
            if !selection_handler.registered {
                selection_handler.registered = true;
                self.poll.register(handle, token, interest, opts)?;
            }
            self.poll.reregister(handle, token, interest, opts)
        }
    }

    pub fn deregister<E>(&mut self, handle: &E, token: Token) -> io::Result<()>
            where E: Evented + ?Sized {
        let selection_handler = self.handlers.remove(token).expect("Unknown token removed");
        if selection_handler.registered {
            self.poll.deregister(handle)?;
        }
        Ok(())
    }

    pub fn poll(&mut self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(events, timeout)
    }

    pub fn run_handler(&mut self, event: Event) {
        let handler = self.handlers.get_mut(event.token()).expect("Token not found").handler.clone();
        handler.borrow_mut().on_ready(self, event);
    }
}
<|endoftext|>


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

//! Memory stuff

use std::mem;

/// How this memory will be used.
#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)]
#[repr(u8)]
pub enum Usage {
    /// Full speed GPU access.
    /// Optimal for render targets and resourced memory.
    Data,
    /// CPU to GPU data flow with update commands.
    /// Used for dynamic buffer data, typically constant buffers.
    Dynamic,
    /// CPU to GPU data flow with mapping.
    /// Used for staging for upload to GPU.
    Upload,
    /// GPU to CPU data flow with mapping.
    /// Used for staging for download from GPU.
    Download,
}

bitflags!(
    /// Memory access
    pub flags Access: u8 {
        /// Read access
        const READ  = 0x1,
        /// Write access
        const WRITE = 0x2,
        /// Full access
        const RW    = 0x3,
    }
);

bitflags!(
    /// Bind flags
    pub flags Bind: u8 {
        /// Can be rendered into.
        const RENDER_TARGET    = 0x1,
        /// Can serve as a depth/stencil target.
        const DEPTH_STENCIL    = 0x2,
        /// Can be bound to the shader for reading.
        const SHADER_RESOURCE  = 0x4,
        /// Can be bound to the shader for writing.
        const UNORDERED_ACCESS = 0x8,
        /// Can be transfered from.
        const TRANSFER_SRC     = 0x10,
        /// Can be transfered into.
        const TRANSFER_DST     = 0x20,
    }
);

impl Bind {
    /// Is this memory bound to be mutated ?
    pub fn is_mutable(&self) -> bool {
        let mutable = TRANSFER_DST | UNORDERED_ACCESS | RENDER_TARGET | DEPTH_STENCIL;
        self.intersects(mutable)
    }
}

/// A service trait used to get the raw data out of strong types.
/// Not meant for public use.
#[doc(hidden)]
pub trait Typed: Sized {
    /// The raw type behind the phantom.
    type Raw;
    /// Crete a new phantom from the raw type.
    fn new(raw: Self::Raw) -> Self;
    /// Get an internal reference to the raw type.
    fn raw(&self) -> &Self::Raw;
}

/// A trait for plain-old-data types.
///
/// A POD type does not have invalid bit patterns and can be safely
/// created from arbitrary bit pattern.
pub unsafe trait Pod {}

macro_rules! impl_pod {
    ( ty = $($ty:ty)* ) => { $( unsafe impl Pod for $ty {} )* };
    ( ar = $($tt:expr)* ) => { $( unsafe impl<T: Pod> Pod for [T; $tt] {} )* };
}

impl_pod! { ty = isize usize i8 u8 i16 u16 i32 u32 i64 u64 f32 f64 }
impl_pod! { ar =
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
}

/// Cast a slice from one POD type to another.
pub fn cast_slice<A: Pod, B: Pod>(slice: &[A]) -> &[B] {
    use std::slice;

    let raw_len = mem::size_of::<A>().wrapping_mul(slice.len());
    let len = raw_len / mem::size_of::<B>();
    assert_eq!(raw_len, mem::size_of::<B>().wrapping_mul(len));
    unsafe {
        slice::from_raw_parts(slice.as_ptr() as *const B, len)
    }
}
<commit_msg>Implement `Pod` for tuples<commit_after>// Copyright 2016 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Memory stuff

use std::mem;

/// How this memory will be used.
#[derive(Eq, Ord, PartialEq, PartialOrd, Hash, Copy, Clone, Debug)]
#[repr(u8)]
pub enum Usage {
    /// Full speed GPU access.
    /// Optimal for render targets and resourced memory.
    Data,
    /// CPU to GPU data flow with update commands.
    /// Used for dynamic buffer data, typically constant buffers.
    Dynamic,
    /// CPU to GPU data flow with mapping.
    /// Used for staging for upload to GPU.
    Upload,
    /// GPU to CPU data flow with mapping.
    /// Used for staging for download from GPU.
    Download,
}

bitflags!(
    /// Memory access
    pub flags Access: u8 {
        /// Read access
        const READ  = 0x1,
        /// Write access
        const WRITE = 0x2,
        /// Full access
        const RW    = 0x3,
    }
);

bitflags!(
    /// Bind flags
    pub flags Bind: u8 {
        /// Can be rendered into.
        const RENDER_TARGET    = 0x1,
        /// Can serve as a depth/stencil target.
        const DEPTH_STENCIL    = 0x2,
        /// Can be bound to the shader for reading.
        const SHADER_RESOURCE  = 0x4,
        /// Can be bound to the shader for writing.
        const UNORDERED_ACCESS = 0x8,
        /// Can be transfered from.
        const TRANSFER_SRC     = 0x10,
        /// Can be transfered into.
        const TRANSFER_DST     = 0x20,
    }
);

impl Bind {
    /// Is this memory bound to be mutated ?
    pub fn is_mutable(&self) -> bool {
        let mutable = TRANSFER_DST | UNORDERED_ACCESS | RENDER_TARGET | DEPTH_STENCIL;
        self.intersects(mutable)
    }
}

/// A service trait used to get the raw data out of strong types.
/// Not meant for public use.
#[doc(hidden)]
pub trait Typed: Sized {
    /// The raw type behind the phantom.
    type Raw;
    /// Crete a new phantom from the raw type.
    fn new(raw: Self::Raw) -> Self;
    /// Get an internal reference to the raw type.
    fn raw(&self) -> &Self::Raw;
}

/// A trait for plain-old-data types.
///
/// A POD type does not have invalid bit patterns and can be safely
/// created from arbitrary bit pattern.
pub unsafe trait Pod {}

macro_rules! impl_pod {
    ( ty = $($ty:ty)* ) => { $( unsafe impl Pod for $ty {} )* };
    ( ar = $($tt:expr)* ) => { $( unsafe impl<T: Pod> Pod for [T; $tt] {} )* };
}

impl_pod! { ty = isize usize i8 u8 i16 u16 i32 u32 i64 u64 f32 f64 }
impl_pod! { ar =
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
}

unsafe impl<T: Pod, U: Pod> Pod for (T, U) {}

/// Cast a slice from one POD type to another.
pub fn cast_slice<A: Pod, B: Pod>(slice: &[A]) -> &[B] {
    use std::slice;

    let raw_len = mem::size_of::<A>().wrapping_mul(slice.len());
    let len = raw_len / mem::size_of::<B>();
    assert_eq!(raw_len, mem::size_of::<B>().wrapping_mul(len));
    unsafe {
        slice::from_raw_parts(slice.as_ptr() as *const B, len)
    }
}
<|endoftext|>


<commit_before>use tokens::*;
use symbols::*;
use symbols::symbol_table::*;
use support::*;
use plp::PLPWriter;

/// @return: (static_memory_label, static_init_label)
pub fn get_class_labels(class_symbol: &Symbol) -> (String, String)
{
    let mut static_memory_label = class_symbol.namespace.clone();
    static_memory_label.push_str("_");
    static_memory_label.push_str(&*class_symbol.name.clone());
    static_memory_label.push_str("_static");

    let mut static_init_label = static_memory_label.to_string();
    static_init_label.push_str("_init");

    (static_memory_label, static_init_label)
}

/// @return: (method_label, return_label)
pub fn get_method_labels(method_symbol: &Symbol) -> (String, String)
{
    let method_label = match method_symbol.location {
        SymbolLocation::Memory(ref address) => address.label_name.clone(),
        _ => { panic!("compile_method_body: Expected Memory address for method"); },
    };

    let mut return_label = method_label.clone();
    return_label.push_str("_return");

    (method_label, return_label)
}

/// @return (memory_label, memory_size)
pub fn get_static_allocation(method_symbol: &Symbol) -> (String, u16)
{
    match method_symbol.symbol_class {
            SymbolClass::Variable(_) => {
                    panic!("Expected Function found Variable");
                },
            SymbolClass::Function(_, _, ref label_name, var_count) => (label_name.clone(), var_count as u16),
            SymbolClass::Structure(ref subtype) => {
                    panic!("Expected Function found {}", subtype);
                }
        }
}

/// @return (memory_label, memory_size)
pub fn get_return_type_of(method_symbol: &Symbol) -> String
{
    match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(ref return_type, _, _, _) => return_type.clone(),
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    }
}

/// @return ([arg1] [, arg2] {, arg3..})
pub fn get_arg_signature_of(method_symbol: &Symbol) -> String
{
    let types: &Vec<String> = match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(_, ref arg_types, _, _) => arg_types,
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    };

    let mut arg_signature = "(".to_string();
    // Handle first arg type
    if types.len() > 0
    {
        arg_signature.push_str(&*types[0]);
        for ref arg_type in types[1..].iter()
        {
            arg_signature.push_str(",");
            arg_signature.push_str(&*arg_type);
        }
    }
    arg_signature.push_str(")");

    arg_signature
}
<commit_msg>Support local initialization<commit_after>use tokens::*;
use symbols::*;
use symbols::symbol_table::*;
use support::*;
use plp::PLPWriter;

/// @return: (static_memory_label, static_init_label, local_init_label)
pub fn get_class_labels(class_symbol: &Symbol) -> (String, String, String)
{
    let mut static_memory_label = class_symbol.namespace.clone();
    static_memory_label.push_str("_");
    static_memory_label.push_str(&*class_symbol.name.clone());
    static_memory_label.push_str("_static");

    let mut local_init_label = class_symbol.namespace.clone();
    local_init_label.push_str("_");
    local_init_label.push_str(&*class_symbol.name.clone());
    local_init_label.push_str("_local_init");

    let mut static_init_label = static_memory_label.to_string();
    static_init_label.push_str("_init");

    (static_memory_label, static_init_label, local_init_label)
}

/// @return: (method_label, return_label)
pub fn get_method_labels(method_symbol: &Symbol) -> (String, String)
{
    let method_label = match method_symbol.location {
        SymbolLocation::Memory(ref address) => address.label_name.clone(),
        _ => { panic!("compile_method_body: Expected Memory address for method"); },
    };

    let mut return_label = method_label.clone();
    return_label.push_str("_return");

    (method_label, return_label)
}

/// @return (memory_label, memory_size)
pub fn get_static_allocation(method_symbol: &Symbol) -> (String, u16)
{
    match method_symbol.symbol_class {
            SymbolClass::Variable(_) => {
                    panic!("Expected Function found Variable");
                },
            SymbolClass::Function(_, _, ref label_name, var_count) => (label_name.clone(), var_count as u16),
            SymbolClass::Structure(ref subtype) => {
                    panic!("Expected Function found {}", subtype);
                }
        }
}

/// @return (memory_label, memory_size)
pub fn get_return_type_of(method_symbol: &Symbol) -> String
{
    match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(ref return_type, _, _, _) => return_type.clone(),
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    }
}

/// @return ([arg1] [, arg2] {, arg3..})
pub fn get_arg_signature_of(method_symbol: &Symbol) -> String
{
    let types: &Vec<String> = match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(_, ref arg_types, _, _) => arg_types,
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    };

    let mut arg_signature = "(".to_string();
    // Handle first arg type
    if types.len() > 0
    {
        arg_signature.push_str(&*types[0]);
        for ref arg_type in types[1..].iter()
        {
            arg_signature.push_str(",");
            arg_signature.push_str(&*arg_type);
        }
    }
    arg_signature.push_str(")");

    arg_signature
}
<|endoftext|>


<commit_before>use tokens::*;
use symbols::*;
use symbols::symbol_table::*;
use support::*;
use plp::PLPWriter;

/// @return: (static_memory_label, static_init_label, local_init_label)
pub fn get_class_labels(class_symbol: &Symbol) -> (String, String, String)
{
    let mut static_memory_label = class_symbol.namespace.clone();
    static_memory_label.push_str("_");
    static_memory_label.push_str(&*class_symbol.name.clone());
    static_memory_label.push_str("_static");

    let mut local_init_label = class_symbol.namespace.clone();
    local_init_label.push_str("_");
    local_init_label.push_str(&*class_symbol.name.clone());
    local_init_label.push_str("_local_init");

    let mut static_init_label = static_memory_label.to_string();
    static_init_label.push_str("_init");

    (static_memory_label, static_init_label, local_init_label)
}

/// @return: (method_label, return_label)
pub fn get_method_labels(method_symbol: &Symbol) -> (String, String)
{
    let method_label = match method_symbol.location {
        SymbolLocation::Memory(ref address) => address.label_name.clone(),
        _ => { panic!("compile_method_body: Expected Memory address for method"); },
    };

    let mut return_label = method_label.clone();
    return_label.push_str("_return");

    (method_label, return_label)
}

/// @return (memory_label, memory_size)
pub fn get_static_allocation(method_symbol: &Symbol) -> (String, u16)
{
    match method_symbol.symbol_class {
            SymbolClass::Variable(_) => {
                    panic!("Expected Function found Variable");
                },
            SymbolClass::Function(_, _, ref label_name, var_count) => (label_name.clone(), var_count as u16),
            SymbolClass::Structure(ref subtype) => {
                    panic!("Expected Function found {}", subtype);
                }
        }
}

/// @return (memory_label, memory_size)
pub fn get_return_type_of(method_symbol: &Symbol) -> String
{
    match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(ref return_type, _, _, _) => return_type.clone(),
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    }
}

/// @return ([arg1] [, arg2] {, arg3..})
pub fn get_arg_signature_of(method_symbol: &Symbol) -> String
{
    let types: &Vec<String> = match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(_, ref arg_types, _, _) => arg_types,
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    };

    let mut arg_signature = "(".to_string();
    // Handle first arg type
    if types.len() > 0
    {
        arg_signature.push_str(&*types[0]);
        for ref arg_type in types[1..].iter()
        {
            arg_signature.push_str(",");
            arg_signature.push_str(&*arg_type);
        }
    }
    arg_signature.push_str(")");

    arg_signature
}
<commit_msg>Do not preface 0 scope class labels with "_"<commit_after>use tokens::*;
use symbols::*;
use symbols::symbol_table::*;
use support::*;
use plp::PLPWriter;

/// @return: (static_memory_label, static_init_label, local_init_label)
pub fn get_class_labels(class_symbol: &Symbol) -> (String, String, String)
{
    let mut namespace_label = class_symbol.namespace.clone();
    if !namespace_label.is_empty() { namespace_label.push_str("_"); }
    namespace_label.push_str(&*class_symbol.name.clone());

    let mut static_memory_label = namespace_label.clone();
    static_memory_label.push_str("_static");

    let mut static_init_label = static_memory_label.to_string();
    static_init_label.push_str("_init");

    let mut local_init_label = namespace_label.clone();
    local_init_label.push_str("_local_init");

    (static_memory_label, static_init_label, local_init_label)
}

/// @return: (method_label, return_label)
pub fn get_method_labels(method_symbol: &Symbol) -> (String, String)
{
    let method_label = match method_symbol.location {
        SymbolLocation::Memory(ref address) => address.label_name.clone(),
        _ => { panic!("compile_method_body: Expected Memory address for method"); },
    };

    let mut return_label = method_label.clone();
    return_label.push_str("_return");

    (method_label, return_label)
}

/// @return (memory_label, memory_size)
pub fn get_static_allocation(method_symbol: &Symbol) -> (String, u16)
{
    match method_symbol.symbol_class {
            SymbolClass::Variable(_) => {
                    panic!("Expected Function found Variable");
                },
            SymbolClass::Function(_, _, ref label_name, var_count) => (label_name.clone(), var_count as u16),
            SymbolClass::Structure(ref subtype) => {
                    panic!("Expected Function found {}", subtype);
                }
        }
}

/// @return (memory_label, memory_size)
pub fn get_return_type_of(method_symbol: &Symbol) -> String
{
    match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(ref return_type, _, _, _) => return_type.clone(),
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    }
}

/// @return ([arg1] [, arg2] {, arg3..})
pub fn get_arg_signature_of(method_symbol: &Symbol) -> String
{
    let types: &Vec<String> = match method_symbol.symbol_class
    {
        SymbolClass::Variable(_) => {
                panic!("Expected Function found Variable");
            },
        SymbolClass::Function(_, ref arg_types, _, _) => arg_types,
        SymbolClass::Structure(ref subtype) => {
                panic!("Expected Function found {}", subtype);
            }
    };

    let mut arg_signature = "(".to_string();
    // Handle first arg type
    if types.len() > 0
    {
        arg_signature.push_str(&*types[0]);
        for ref arg_type in types[1..].iter()
        {
            arg_signature.push_str(",");
            arg_signature.push_str(&*arg_type);
        }
    }
    arg_signature.push_str(")");

    arg_signature
}
<|endoftext|>


<commit_before>use rusqlite::Connection;

#[derive(Debug)]
pub struct JobRequireVariable {
    id: i32,
    fk_job: i32,
    fk_variable: i32,
}

pub fn table_create_job_require_variable(conn: &Connection) {
    conn.execute(
        "CREATE TABLE JOB_REQUIRE_VARIABLE (
                  id                    INTEGER PRIMARY KEY ASC,
                  fk_job                INTEGER NOT NULL,
                  fk_variable           INTEGER NOT NULL,
                  FOREIGN KEY(fk_job) REFERENCES JOB(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable) REFERENCES JOB_REQUIRE_VARIABLE(id) ON UPDATE CASCADE
                  )",
        &[],
    ).unwrap();
}

pub fn insert_job_require_variable(
    conn: &Connection,
    job: &i32,
    variable: &i32,
) -> Result<i32, &'static str> {
    let me = JobRequireVariable {
        id: 0,
        fk_job: *job,
        fk_variable: *variable,
    };
    let job_require_variable_instance = conn.execute(
        "INSERT INTO JOB_REQUIRE_VARIABLE (fk_job, fk_variable)
                  VALUES (?1, ?2)",
        &[&me.fk_job, &me.fk_variable],
    );
    if job_require_variable_instance.is_err() {
        return Err("Insert failed");
    }
    job_require_variable_instance.unwrap();
    return Ok(0);
}

pub fn list_job_require_variable(conn: &Connection) -> Vec<JobRequireVariable> {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable  FROM JOB_REQUIRE_VARIABLE")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        JobRequireVariable {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
        }
    });
    let mut items = Vec::<JobRequireVariable>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn job_require_variable_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable  FROM JOB_REQUIRE_VARIABLE")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        JobRequireVariable {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        info!("Found job_require_variable {:?}", person.unwrap());
    }
}

pub fn pk_job_require_variable_by_name(
    conn: &Connection,
    job: &i32,
    variable: &i32,
    pk: &mut i32,
) -> Result<i32, &'static str> {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable  FROM JOB_REQUIRE_VARIABLE WHERE fk_job = ?1 AND fk_variable = ?2").unwrap();
    let job_require_variable_iter = stmt.query_map(&[job, variable], |row| {
        JobRequireVariable {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
        }
    });
    if job_require_variable_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = job_require_variable_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        *pk = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(found);
    }
    return Err("None found");
}
<commit_msg>Bugfix pk_job_require_variable_by_name<commit_after>use rusqlite::Connection;

#[derive(Debug)]
pub struct JobRequireVariable {
    id: i32,
    fk_job: i32,
    fk_variable: i32,
}

pub fn table_create_job_require_variable(conn: &Connection) {
    conn.execute(
        "CREATE TABLE JOB_REQUIRE_VARIABLE (
                  id                    INTEGER PRIMARY KEY ASC,
                  fk_job                INTEGER NOT NULL,
                  fk_variable           INTEGER NOT NULL,
                  FOREIGN KEY(fk_job) REFERENCES JOB(id) ON UPDATE CASCADE
                  FOREIGN KEY(fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    ).unwrap();
}

pub fn insert_job_require_variable(
    conn: &Connection,
    job: &i32,
    variable: &i32,
) -> Result<i32, &'static str> {
    let me = JobRequireVariable {
        id: 0,
        fk_job: *job,
        fk_variable: *variable,
    };
    let job_require_variable_instance = conn.execute(
        "INSERT INTO JOB_REQUIRE_VARIABLE (fk_job, fk_variable)
                  VALUES (?1, ?2)",
        &[&me.fk_job, &me.fk_variable],
    );
    if job_require_variable_instance.is_err() {
        return Err("INSERT INTO JOB_REQUIRE_VARIABLE failed");
    }
    job_require_variable_instance.unwrap();
    return Ok(0);
}

pub fn list_job_require_variable(conn: &Connection) -> Vec<JobRequireVariable> {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable  FROM JOB_REQUIRE_VARIABLE")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        JobRequireVariable {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
        }
    });
    let mut items = Vec::<JobRequireVariable>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn job_require_variable_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable  FROM JOB_REQUIRE_VARIABLE")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        JobRequireVariable {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        info!("Found job_require_variable {:?}", person.unwrap());
    }
}

pub fn pk_job_require_variable_by_name(
    conn: &Connection,
    job: &i32,
    variable: &i32,
) -> Result<i32, &'static str> {
    let mut stmt = conn.prepare("SELECT id, fk_job, fk_variable  FROM JOB_REQUIRE_VARIABLE WHERE fk_job = ?1 AND fk_variable = ?2").unwrap();
    let job_require_variable_iter = stmt.query_map(&[job, variable], |row| {
        JobRequireVariable {
            id: row.get(0),
            fk_job: row.get(1),
            fk_variable: row.get(2),
        }
    });
    if job_require_variable_iter.is_err() {
        return Err("Insert failed dfdf");
    }
    let result = job_require_variable_iter.unwrap();
    let mut found = 0;
    let mut output = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
        break;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! PageHandler manages the page states of multiple regions.

#![deny(missing_docs)]

use std::ops::Range;
use std::path::Path;

use base::error;
use base::pagesize;
use base::unix::FileDataIterator;
use base::AsRawDescriptor;
use data_model::VolatileSlice;
use thiserror::Error as ThisError;

use crate::file::Error as FileError;
use crate::file::SwapFile;
use crate::userfaultfd::UffdError;
use crate::userfaultfd::Userfaultfd;

/// Result for PageHandler
pub type Result<T> = std::result::Result<T, Error>;

/// Errors for PageHandler
#[derive(ThisError, Debug)]
pub enum Error {
    #[error("the address is invalid {0:#018X}")]
    /// the address is invalid
    InvalidAddress(usize),
    #[error("the regions {0:?} and {1:?} overlap")]
    /// regions are overlaps on registering
    RegionOverlap(Range<usize>, Range<usize>),
    #[error("file operation failed : {0:?}")]
    /// file operation failed
    File(FileError),
    #[error("userfaultfd failed : {0:?}")]
    /// userfaultfd operation failed
    Userfaultfd(UffdError),
}

impl From<UffdError> for Error {
    fn from(e: UffdError) -> Self {
        Self::Userfaultfd(e)
    }
}

impl From<FileError> for Error {
    fn from(e: FileError) -> Self {
        Self::File(e)
    }
}

/// [Region] represents a memory region and corresponding [SwapFile].
struct Region {
    /// the head page index of the region.
    head_page_idx: usize,
    file: SwapFile,
}

/// PageHandler manages the page states of multiple regions.
///
/// Handles multiple events derived from userfaultfd and swap out requests.
/// All the addresses and sizes in bytes are converted to page id internally.
pub struct PageHandler {
    regions: Vec<Region>,
    pagesize_shift: u32,
}

impl PageHandler {
    /// Creates [PageHandler] and [SwapFile] corresponding to each region.
    ///
    /// # Arguments
    ///
    /// * `swap_dir` - path to the directory to create a swap file from.
    /// * `regions` - the list of the region. the start address must align with page. the size must
    ///   be multiple of pagesize.
    pub fn create(swap_dir: &Path, regions: &[Range<usize>]) -> Result<Self> {
        let pagesize_shift = pagesize().trailing_zeros();
        // pagesize() should be power of 2 in almost all cases. vmm-swap feature does not support
        // systems in which page size is not power of 2.
        if 1 << pagesize_shift != pagesize() {
            panic!("page size is not power of 2");
        }

        let mut handler = Self {
            regions: Vec::new(),
            pagesize_shift,
        };

        for address_range in regions {
            handler.add_region(swap_dir, address_range)?;
        }

        Ok(handler)
    }

    /// The page index of the page which contains the "addr".
    fn addr_to_page_idx(&self, addr: usize) -> usize {
        addr >> self.pagesize_shift
    }

    /// The head address of the page.
    fn page_idx_to_addr(&self, page_idx: usize) -> usize {
        page_idx << self.pagesize_shift
    }

    /// The head address of the page which contains the "addr".
    fn page_base_addr(&self, addr: usize) -> usize {
        (addr >> self.pagesize_shift) << self.pagesize_shift
    }

    fn is_page_aligned(&self, addr: usize) -> bool {
        let mask = (1 << self.pagesize_shift) - 1;
        addr & mask == 0
    }

    fn find_region_position(&self, page_idx: usize) -> Option<usize> {
        // sequential search the corresponding page map from the list. It should be fast enough
        // because there are a few regions (usually only 1).
        self.regions.iter().position(|region| {
            region.head_page_idx <= page_idx && page_idx < region.head_page_idx + region.file.len()
        })
    }

    fn find_region(&mut self, page_idx: usize) -> Option<&mut Region> {
        self.find_region_position(page_idx)
            .map(|i| &mut self.regions[i])
    }

    /// Create a new internal context to handle userfaultfd events and swap in/out request.
    ///
    /// If the regions overlaps an existing region, it returns [Error::RegionOverlap].
    ///
    /// # Arguments
    ///
    /// * `swap_dir` - path to the directory to create a swap file from.
    /// * `address_range` - the range of the region. the start address must align with page. the
    ///   size must be multiple of pagesize.
    fn add_region(&mut self, swap_dir: &Path, address_range: &Range<usize>) -> Result<()> {
        let head_page_idx = self.addr_to_page_idx(address_range.start);
        let region_size = address_range.end - address_range.start;
        let num_of_pages = region_size >> self.pagesize_shift;

        // find an overlaping region
        match self.regions.iter().position(|region| {
            if region.head_page_idx < head_page_idx {
                region.head_page_idx + region.file.len() > head_page_idx
            } else {
                region.head_page_idx < head_page_idx + num_of_pages
            }
        }) {
            Some(i) => {
                let region = &self.regions[i];

                Err(Error::RegionOverlap(
                    address_range.clone(),
                    self.page_idx_to_addr(region.head_page_idx)
                        ..(self.page_idx_to_addr(region.head_page_idx + region.file.len())),
                ))
            }
            None => {
                let base_addr = address_range.start;
                assert!(self.is_page_aligned(base_addr));
                assert!(self.is_page_aligned(region_size));

                let file = SwapFile::new(swap_dir, num_of_pages)?;
                self.regions.push(Region {
                    head_page_idx,
                    file,
                });
                Ok(())
            }
        }
    }

    fn copy_all(
        uffd: &Userfaultfd,
        page_addr: usize,
        mut data_slice: VolatileSlice,
        wake: bool,
    ) -> std::result::Result<(), UffdError> {
        loop {
            let result = uffd.copy(page_addr, data_slice.size(), data_slice.as_ptr(), wake);
            match result {
                Err(UffdError::PartiallyCopied(copied)) => {
                    data_slice.advance(copied);
                }
                other => {
                    // Even EEXIST for copy operation should be an error for page fault handling. If
                    // the page was swapped in before, the page should be cleared from the swap file
                    // and do `Userfaultfd::zero()` instead.
                    return other.map(|_| ());
                }
            }
        }
    }

    /// Fills the faulted page with zero if the page is not initialized, with the content in the
    /// swap file if the page is swapped out.
    ///
    /// # Arguments
    ///
    /// * `uffd` - the reference to the [Userfaultfd] for the faulting process.
    /// * `address` - the address that triggered the page fault.
    pub fn handle_page_fault(&mut self, uffd: &Userfaultfd, address: usize) -> Result<()> {
        let page_idx = self.addr_to_page_idx(address);
        // the head address of the page.
        let page_addr = self.page_base_addr(address);
        let Region {
            head_page_idx,
            file,
        } = self
            .find_region(page_idx)
            .ok_or(Error::InvalidAddress(address))?;

        let idx_in_region = page_idx - *head_page_idx;
        match file.page_content(idx_in_region)? {
            Some(page_slice) => {
                Self::copy_all(uffd, page_addr, page_slice, true)?;
                file.clear(idx_in_region)?;
                Ok(())
            }
            None => {
                // Map a zero page since no swap file has been created yet but the fault happened.
                // safe because the fault page is notified by uffd.
                let result = uffd.zero(page_addr, 1 << self.pagesize_shift, true);
                match result {
                    Ok(_) => Ok(()),
                    Err(UffdError::ZeropageFailed(errno)) if errno as i32 == libc::EEXIST => {
                        // zeroing fails with EEXIST if the page is already filled. This case can
                        // happen if page faults on the same page happen on different processes.
                        Ok(())
                    }
                    Err(e) => Err(e.into()),
                }
            }
        }
    }

    /// Clear the internal state for the pages.
    ///
    /// When pages are removed by madvise with `MADV_DONTNEED` or `MADV_REMOVE`, userfaultfd
    /// notifies the event as `UFFD_EVENT_REMOVE`. This handles the remove event.
    ///
    /// In crosvm, balloon frees the guest memory and cause `UFFD_EVENT_REMOVE`.
    ///
    /// # Arguments
    ///
    /// * `start_addr` - the head address of the memory area to be freed.
    /// * `end_addr` - the end address of the memory area to be freed. `UFFD_EVENT_REMOVE` tells the
    ///   head address of the next memory area of the freed area. (i.e. the exact tail address of
    ///   the memory area is `end_addr - 1`.)
    pub fn handle_page_remove(&mut self, start_addr: usize, end_addr: usize) -> Result<()> {
        if !self.is_page_aligned(start_addr) {
            return Err(Error::InvalidAddress(start_addr));
        } else if !self.is_page_aligned(end_addr) {
            return Err(Error::InvalidAddress(end_addr));
        }
        let start_page_idx = self.addr_to_page_idx(start_addr);
        let last_page_idx = self.addr_to_page_idx(end_addr);
        for page_idx in start_page_idx..(last_page_idx) {
            let page_addr = self.page_idx_to_addr(page_idx);
            let region = self
                .find_region(page_idx)
                .ok_or(Error::InvalidAddress(page_addr))?;
            if let Err(e) = region.file.clear(page_idx - region.head_page_idx) {
                error!("failed to clear removed page: {:?}", e);
            }
        }
        Ok(())
    }

    /// Write active pages in the memory region to the swap file.
    ///
    /// It only writes active contents in the guest memory to the swap file and skips empty
    /// pages (e.g. pages not touched, freed by balloon) using `lseek(2)` + `SEEK_HOLE/DATA`.
    ///
    /// The memory must be protected not to be updated during swapped out.
    ///
    /// # Arguments
    ///
    /// * `base_addr` - the head address of the memory region to swap out.
    /// * `memfd` - the file descriptor of the memfd backing the guest memory region.
    /// * `base_offset` - the offset of the memory region in the memfd.
    ///
    /// # Safety
    ///
    /// The region must have been registered to all userfaultfd of processes which may touch the
    /// region.
    ///
    /// The page fault events for the region from the userfaultfd must be handled by
    /// [PageHandler::handle_page_fault].
    #[deny(unsafe_op_in_unsafe_fn)]
    pub unsafe fn swap_out<T>(
        &mut self,
        base_addr: usize,
        memfd: &T,
        base_offset: u64,
    ) -> Result<()>
    where
        T: AsRawDescriptor,
    {
        let head_page_idx = self.addr_to_page_idx(base_addr);
        // use find_region_position instead of find_region() due to borrow checker.
        let region_position = self
            .find_region_position(head_page_idx)
            .ok_or(Error::InvalidAddress(base_addr))?;
        if self.regions[region_position].head_page_idx != head_page_idx {
            return Err(Error::InvalidAddress(base_addr));
        }
        let region_size = self.regions[region_position].file.len() << self.pagesize_shift;
        let file_data = FileDataIterator::new(memfd, base_offset);

        for data_range in file_data {
            // assert offset is page aligned
            let offset = (data_range.start - base_offset) as usize;
            assert!(self.is_page_aligned(offset));
            let addr = base_addr + offset;
            let page_idx = self.addr_to_page_idx(addr);
            let size = (data_range.end - data_range.start) as usize;
            assert!(self.is_page_aligned(size));
            // safe because the page is within the range of the guest memory.
            let mem_slice = unsafe { std::slice::from_raw_parts(addr as *const u8, size) };
            self.regions[region_position]
                .file
                .write_to_file(page_idx - head_page_idx, mem_slice)?
            // TODO(kawasin): periodically MADV_REMOVE the guest memory. if the pages are in zram,
            // it increases the RAM usage during swap_out.
            // TODO(kawasin): free the page cache of the swap file. or direct I/O.
        }

        // safe because the region is already backed by the file and the content will be swapped in
        // on a page fault.
        unsafe {
            libc::madvise(
                base_addr as *mut libc::c_void,
                region_size,
                libc::MADV_REMOVE,
            );
        }

        Ok(())
    }

    /// Swap in all the content.
    ///
    /// # Arguments
    ///
    /// * `uffd` - the main [Userfaultfd].
    pub fn swap_in(self, uffd: &Userfaultfd) -> Result<()> {
        for region in self.regions.iter() {
            for pages in region.file.all_present_pages() {
                let page_idx = region.head_page_idx + pages.base_idx;
                let page_addr = self.page_idx_to_addr(page_idx);
                Self::copy_all(uffd, page_addr, pages.content, false)?;
            }
        }
        Ok(())
    }
}
<commit_msg>swap: fix cursor in PageHandler::copy_all()<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! PageHandler manages the page states of multiple regions.

#![deny(missing_docs)]

use std::ops::Range;
use std::path::Path;

use base::error;
use base::pagesize;
use base::unix::FileDataIterator;
use base::AsRawDescriptor;
use data_model::VolatileSlice;
use thiserror::Error as ThisError;

use crate::file::Error as FileError;
use crate::file::SwapFile;
use crate::userfaultfd::UffdError;
use crate::userfaultfd::Userfaultfd;

/// Result for PageHandler
pub type Result<T> = std::result::Result<T, Error>;

/// Errors for PageHandler
#[derive(ThisError, Debug)]
pub enum Error {
    #[error("the address is invalid {0:#018X}")]
    /// the address is invalid
    InvalidAddress(usize),
    #[error("the regions {0:?} and {1:?} overlap")]
    /// regions are overlaps on registering
    RegionOverlap(Range<usize>, Range<usize>),
    #[error("file operation failed : {0:?}")]
    /// file operation failed
    File(FileError),
    #[error("userfaultfd failed : {0:?}")]
    /// userfaultfd operation failed
    Userfaultfd(UffdError),
}

impl From<UffdError> for Error {
    fn from(e: UffdError) -> Self {
        Self::Userfaultfd(e)
    }
}

impl From<FileError> for Error {
    fn from(e: FileError) -> Self {
        Self::File(e)
    }
}

/// [Region] represents a memory region and corresponding [SwapFile].
struct Region {
    /// the head page index of the region.
    head_page_idx: usize,
    file: SwapFile,
}

/// PageHandler manages the page states of multiple regions.
///
/// Handles multiple events derived from userfaultfd and swap out requests.
/// All the addresses and sizes in bytes are converted to page id internally.
pub struct PageHandler {
    regions: Vec<Region>,
    pagesize_shift: u32,
}

impl PageHandler {
    /// Creates [PageHandler] and [SwapFile] corresponding to each region.
    ///
    /// # Arguments
    ///
    /// * `swap_dir` - path to the directory to create a swap file from.
    /// * `regions` - the list of the region. the start address must align with page. the size must
    ///   be multiple of pagesize.
    pub fn create(swap_dir: &Path, regions: &[Range<usize>]) -> Result<Self> {
        let pagesize_shift = pagesize().trailing_zeros();
        // pagesize() should be power of 2 in almost all cases. vmm-swap feature does not support
        // systems in which page size is not power of 2.
        if 1 << pagesize_shift != pagesize() {
            panic!("page size is not power of 2");
        }

        let mut handler = Self {
            regions: Vec::new(),
            pagesize_shift,
        };

        for address_range in regions {
            handler.add_region(swap_dir, address_range)?;
        }

        Ok(handler)
    }

    /// The page index of the page which contains the "addr".
    fn addr_to_page_idx(&self, addr: usize) -> usize {
        addr >> self.pagesize_shift
    }

    /// The head address of the page.
    fn page_idx_to_addr(&self, page_idx: usize) -> usize {
        page_idx << self.pagesize_shift
    }

    /// The head address of the page which contains the "addr".
    fn page_base_addr(&self, addr: usize) -> usize {
        (addr >> self.pagesize_shift) << self.pagesize_shift
    }

    fn is_page_aligned(&self, addr: usize) -> bool {
        let mask = (1 << self.pagesize_shift) - 1;
        addr & mask == 0
    }

    fn find_region_position(&self, page_idx: usize) -> Option<usize> {
        // sequential search the corresponding page map from the list. It should be fast enough
        // because there are a few regions (usually only 1).
        self.regions.iter().position(|region| {
            region.head_page_idx <= page_idx && page_idx < region.head_page_idx + region.file.len()
        })
    }

    fn find_region(&mut self, page_idx: usize) -> Option<&mut Region> {
        self.find_region_position(page_idx)
            .map(|i| &mut self.regions[i])
    }

    /// Create a new internal context to handle userfaultfd events and swap in/out request.
    ///
    /// If the regions overlaps an existing region, it returns [Error::RegionOverlap].
    ///
    /// # Arguments
    ///
    /// * `swap_dir` - path to the directory to create a swap file from.
    /// * `address_range` - the range of the region. the start address must align with page. the
    ///   size must be multiple of pagesize.
    fn add_region(&mut self, swap_dir: &Path, address_range: &Range<usize>) -> Result<()> {
        let head_page_idx = self.addr_to_page_idx(address_range.start);
        let region_size = address_range.end - address_range.start;
        let num_of_pages = region_size >> self.pagesize_shift;

        // find an overlaping region
        match self.regions.iter().position(|region| {
            if region.head_page_idx < head_page_idx {
                region.head_page_idx + region.file.len() > head_page_idx
            } else {
                region.head_page_idx < head_page_idx + num_of_pages
            }
        }) {
            Some(i) => {
                let region = &self.regions[i];

                Err(Error::RegionOverlap(
                    address_range.clone(),
                    self.page_idx_to_addr(region.head_page_idx)
                        ..(self.page_idx_to_addr(region.head_page_idx + region.file.len())),
                ))
            }
            None => {
                let base_addr = address_range.start;
                assert!(self.is_page_aligned(base_addr));
                assert!(self.is_page_aligned(region_size));

                let file = SwapFile::new(swap_dir, num_of_pages)?;
                self.regions.push(Region {
                    head_page_idx,
                    file,
                });
                Ok(())
            }
        }
    }

    fn copy_all(
        uffd: &Userfaultfd,
        mut page_addr: usize,
        mut data_slice: VolatileSlice,
        wake: bool,
    ) -> std::result::Result<(), UffdError> {
        loop {
            let result = uffd.copy(page_addr, data_slice.size(), data_slice.as_ptr(), wake);
            match result {
                Err(UffdError::PartiallyCopied(copied)) => {
                    page_addr += copied;
                    data_slice.advance(copied);
                }
                other => {
                    // Even EEXIST for copy operation should be an error for page fault handling. If
                    // the page was swapped in before, the page should be cleared from the swap file
                    // and do `Userfaultfd::zero()` instead.
                    return other.map(|_| ());
                }
            }
        }
    }

    /// Fills the faulted page with zero if the page is not initialized, with the content in the
    /// swap file if the page is swapped out.
    ///
    /// # Arguments
    ///
    /// * `uffd` - the reference to the [Userfaultfd] for the faulting process.
    /// * `address` - the address that triggered the page fault.
    pub fn handle_page_fault(&mut self, uffd: &Userfaultfd, address: usize) -> Result<()> {
        let page_idx = self.addr_to_page_idx(address);
        // the head address of the page.
        let page_addr = self.page_base_addr(address);
        let Region {
            head_page_idx,
            file,
        } = self
            .find_region(page_idx)
            .ok_or(Error::InvalidAddress(address))?;

        let idx_in_region = page_idx - *head_page_idx;
        match file.page_content(idx_in_region)? {
            Some(page_slice) => {
                Self::copy_all(uffd, page_addr, page_slice, true)?;
                file.clear(idx_in_region)?;
                Ok(())
            }
            None => {
                // Map a zero page since no swap file has been created yet but the fault happened.
                // safe because the fault page is notified by uffd.
                let result = uffd.zero(page_addr, 1 << self.pagesize_shift, true);
                match result {
                    Ok(_) => Ok(()),
                    Err(UffdError::ZeropageFailed(errno)) if errno as i32 == libc::EEXIST => {
                        // zeroing fails with EEXIST if the page is already filled. This case can
                        // happen if page faults on the same page happen on different processes.
                        Ok(())
                    }
                    Err(e) => Err(e.into()),
                }
            }
        }
    }

    /// Clear the internal state for the pages.
    ///
    /// When pages are removed by madvise with `MADV_DONTNEED` or `MADV_REMOVE`, userfaultfd
    /// notifies the event as `UFFD_EVENT_REMOVE`. This handles the remove event.
    ///
    /// In crosvm, balloon frees the guest memory and cause `UFFD_EVENT_REMOVE`.
    ///
    /// # Arguments
    ///
    /// * `start_addr` - the head address of the memory area to be freed.
    /// * `end_addr` - the end address of the memory area to be freed. `UFFD_EVENT_REMOVE` tells the
    ///   head address of the next memory area of the freed area. (i.e. the exact tail address of
    ///   the memory area is `end_addr - 1`.)
    pub fn handle_page_remove(&mut self, start_addr: usize, end_addr: usize) -> Result<()> {
        if !self.is_page_aligned(start_addr) {
            return Err(Error::InvalidAddress(start_addr));
        } else if !self.is_page_aligned(end_addr) {
            return Err(Error::InvalidAddress(end_addr));
        }
        let start_page_idx = self.addr_to_page_idx(start_addr);
        let last_page_idx = self.addr_to_page_idx(end_addr);
        for page_idx in start_page_idx..(last_page_idx) {
            let page_addr = self.page_idx_to_addr(page_idx);
            let region = self
                .find_region(page_idx)
                .ok_or(Error::InvalidAddress(page_addr))?;
            if let Err(e) = region.file.clear(page_idx - region.head_page_idx) {
                error!("failed to clear removed page: {:?}", e);
            }
        }
        Ok(())
    }

    /// Write active pages in the memory region to the swap file.
    ///
    /// It only writes active contents in the guest memory to the swap file and skips empty
    /// pages (e.g. pages not touched, freed by balloon) using `lseek(2)` + `SEEK_HOLE/DATA`.
    ///
    /// The memory must be protected not to be updated during swapped out.
    ///
    /// # Arguments
    ///
    /// * `base_addr` - the head address of the memory region to swap out.
    /// * `memfd` - the file descriptor of the memfd backing the guest memory region.
    /// * `base_offset` - the offset of the memory region in the memfd.
    ///
    /// # Safety
    ///
    /// The region must have been registered to all userfaultfd of processes which may touch the
    /// region.
    ///
    /// The page fault events for the region from the userfaultfd must be handled by
    /// [PageHandler::handle_page_fault].
    #[deny(unsafe_op_in_unsafe_fn)]
    pub unsafe fn swap_out<T>(
        &mut self,
        base_addr: usize,
        memfd: &T,
        base_offset: u64,
    ) -> Result<()>
    where
        T: AsRawDescriptor,
    {
        let head_page_idx = self.addr_to_page_idx(base_addr);
        // use find_region_position instead of find_region() due to borrow checker.
        let region_position = self
            .find_region_position(head_page_idx)
            .ok_or(Error::InvalidAddress(base_addr))?;
        if self.regions[region_position].head_page_idx != head_page_idx {
            return Err(Error::InvalidAddress(base_addr));
        }
        let region_size = self.regions[region_position].file.len() << self.pagesize_shift;
        let file_data = FileDataIterator::new(memfd, base_offset);

        for data_range in file_data {
            // assert offset is page aligned
            let offset = (data_range.start - base_offset) as usize;
            assert!(self.is_page_aligned(offset));
            let addr = base_addr + offset;
            let page_idx = self.addr_to_page_idx(addr);
            let size = (data_range.end - data_range.start) as usize;
            assert!(self.is_page_aligned(size));
            // safe because the page is within the range of the guest memory.
            let mem_slice = unsafe { std::slice::from_raw_parts(addr as *const u8, size) };
            self.regions[region_position]
                .file
                .write_to_file(page_idx - head_page_idx, mem_slice)?
            // TODO(kawasin): periodically MADV_REMOVE the guest memory. if the pages are in zram,
            // it increases the RAM usage during swap_out.
            // TODO(kawasin): free the page cache of the swap file. or direct I/O.
        }

        // safe because the region is already backed by the file and the content will be swapped in
        // on a page fault.
        unsafe {
            libc::madvise(
                base_addr as *mut libc::c_void,
                region_size,
                libc::MADV_REMOVE,
            );
        }

        Ok(())
    }

    /// Swap in all the content.
    ///
    /// # Arguments
    ///
    /// * `uffd` - the main [Userfaultfd].
    pub fn swap_in(self, uffd: &Userfaultfd) -> Result<()> {
        for region in self.regions.iter() {
            for pages in region.file.all_present_pages() {
                let page_idx = region.head_page_idx + pages.base_idx;
                let page_addr = self.page_idx_to_addr(page_idx);
                Self::copy_all(uffd, page_addr, pages.content, false)?;
            }
        }
        Ok(())
    }
}
<|endoftext|>