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

use super::free_regions::FreeRegions;
use rustc::infer::InferCtxt;
use rustc::infer::RegionVariableOrigin;
use rustc::infer::NLLRegionVariableOrigin;
use rustc::infer::region_constraints::VarOrigins;
use rustc::mir::{Location, Mir};
use rustc::ty::{self, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashSet;
use std::collections::BTreeSet;
use std::fmt;
use syntax_pos::Span;

pub struct RegionInferenceContext<'tcx> {
    /// Contains the definition for every region variable.  Region
    /// variables are identified by their index (`RegionVid`). The
    /// definition contains information about where the region came
    /// from as well as its final inferred value.
    definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,

    /// The constraints we have accumulated and used during solving.
    constraints: Vec<Constraint>,
}

struct RegionDefinition<'tcx> {
    /// Why we created this variable. Mostly these will be
    /// `RegionVariableOrigin::NLL`, but some variables get created
    /// elsewhere in the code with other causes (e.g., instantiation
    /// late-bound-regions).
    origin: RegionVariableOrigin,

    /// If this is a free-region, then this is `Some(X)` where `X` is
    /// the name of the region.
    name: Option<ty::Region<'tcx>>,

    /// If true, this is a constant region which cannot grow larger.
    /// This is used for named regions as well as `'static`.
    constant: bool,

    /// The current value of this inference variable. This starts out
    /// empty, but grows as we add constraints. The final value is
    /// determined when `solve()` is executed.
    value: Region,
}

/// The value of an individual region variable. Region variables
/// consist of a set of points in the CFG as well as a set of "free
/// regions", which are sometimes written as `end(R)`. These
/// correspond to the named lifetimes and refer to portions of the
/// caller's control-flow graph -- specifically some portion that can
/// be reached after we return.
#[derive(Clone, Default, PartialEq, Eq)]
struct Region {
    points: BTreeSet<Location>,
    free_regions: BTreeSet<RegionVid>,
}

impl fmt::Debug for Region {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        formatter
            .debug_set()
            .entries(&self.points)
            .entries(&self.free_regions)
            .finish()
    }
}

impl Region {
    fn add_point(&mut self, point: Location) -> bool {
        self.points.insert(point)
    }

    fn add_free_region(&mut self, region: RegionVid) -> bool {
        self.free_regions.insert(region)
    }

    fn contains_point(&self, point: Location) -> bool {
        self.points.contains(&point)
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Constraint {
    /// Where did this constraint arise?
    span: Span,

    /// The region SUP must outlive SUB...
    sup: RegionVid,

    /// Region that must be outlived.
    sub: RegionVid,

    /// At this location.
    point: Location,
}

impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
    /// Creates a new region inference context with a total of
    /// `num_region_variables` valid inference variables; the first N
    /// of those will be constant regions representing the free
    /// regions defined in `free_regions`.
    pub fn new(var_origins: VarOrigins, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) -> Self {
        // Create a RegionDefinition for each inference variable.
        let definitions = var_origins
            .into_iter()
            .map(|origin| RegionDefinition::new(origin))
            .collect();

        let mut result = Self {
            definitions: definitions,
            constraints: Vec::new(),
        };

        result.init_free_regions(free_regions, mir);

        result
    }

    /// Initializes the region variables for each free region
    /// (lifetime parameter). The first N variables always correspond
    /// to the free regions appearing in the function signature (both
    /// named and anonymous) and where clauses. This function iterates
    /// over those regions and initializes them with minimum values.
    ///
    /// For example:
    ///
    ///     fn foo<'a, 'b>(..) where 'a: 'b
    ///
    /// would initialize two variables like so:
    ///
    ///     R0 = { CFG, R0 } // 'a
    ///     R1 = { CFG, R0, R1 } // 'b
    ///
    /// Here, R0 represents `'a`, and it contains (a) the entire CFG
    /// and (b) any free regions that it outlives, which in this case
    /// is just itself. R1 (`'b`) in contrast also outlives `'a` and
    /// hence contains R0 and R1.
    fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) {
        let FreeRegions {
            indices,
            free_region_map,
        } = free_regions;

        // For each free region X:
        for (free_region, &variable) in indices {
            // These should be free-region variables.
            assert!(match self.definitions[variable].origin {
                RegionVariableOrigin::NLL(NLLRegionVariableOrigin::FreeRegion) => true,
                _ => false,
            });

            // Initialize the name and a few other details.
            self.definitions[variable].name = Some(free_region);
            self.definitions[variable].constant = true;

            // Add all nodes in the CFG to `definition.value`.
            for (block, block_data) in mir.basic_blocks().iter_enumerated() {
                let definition = &mut self.definitions[variable];
                for statement_index in 0..block_data.statements.len() + 1 {
                    let location = Location {
                        block,
                        statement_index,
                    };
                    definition.value.add_point(location);
                }
            }

            // Add `end(X)` into the set for X.
            self.definitions[variable].value.add_free_region(variable);

            // Go through each region Y that outlives X (i.e., where
            // Y: X is true). Add `end(X)` into the set for `Y`.
            for superregion in free_region_map.regions_that_outlive(&free_region) {
                let superregion_index = indices[superregion];
                self.definitions[superregion_index]
                    .value
                    .add_free_region(variable);
            }

            debug!(
                "init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`",
                free_region,
                variable,
                self.definitions[variable].value
            );
        }
    }

    /// Returns an iterator over all the region indices.
    pub fn regions(&self) -> impl Iterator<Item = RegionVid> {
        self.definitions.indices()
    }

    /// Returns true if the region `r` contains the point `p`.
    ///
    /// Until `solve()` executes, this value is not particularly meaningful.
    pub fn region_contains_point(&self, r: RegionVid, p: Location) -> bool {
        self.definitions[r].value.contains_point(p)
    }

    /// Returns access to the value of `r` for debugging purposes.
    pub(super) fn region_value(&self, r: RegionVid) -> &fmt::Debug {
        &self.definitions[r].value
    }

    /// Indicates that the region variable `v` is live at the point `point`.
    pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) {
        debug!("add_live_point({:?}, {:?})", v, point);
        let definition = &mut self.definitions[v];
        if !definition.constant {
            definition.value.add_point(point);
        } else {
            // Constants are used for free regions, which already
            // contain all the points in the control-flow graph.
            assert!(definition.value.contains_point(point));
        }
    }

    /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
    pub(super) fn add_outlives(
        &mut self,
        span: Span,
        sup: RegionVid,
        sub: RegionVid,
        point: Location,
    ) {
        debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
        self.constraints.push(Constraint {
            span,
            sup,
            sub,
            point,
        });
    }

    /// Perform region inference.
    pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
        let errors = self.propagate_constraints(mir);

        // worst error msg ever
        for (fr1, span, fr2) in errors {
            infcx.tcx.sess.span_err(
                span,
                &format!(
                    "free region `{}` does not outlive `{}`",
                    self.definitions[fr1].name.unwrap(),
                    self.definitions[fr2].name.unwrap()
                ),
            );
        }
    }

    /// Propagate the region constraints: this will grow the values
    /// for each region variable until all the constraints are
    /// satisfied. Note that some values may grow **too** large to be
    /// feasible, but we check this later.
    fn propagate_constraints(&mut self, mir: &Mir<'tcx>) -> Vec<(RegionVid, Span, RegionVid)> {
        let mut changed = true;
        let mut dfs = Dfs::new(mir);
        let mut error_regions = FxHashSet();
        let mut errors = vec![];
        while changed {
            changed = false;
            for constraint in &self.constraints {
                debug!("constraint: {:?}", constraint);
                let sub = &self.definitions[constraint.sub].value.clone();
                let sup_def = &mut self.definitions[constraint.sup];

                debug!("    sub (before): {:?}", sub);
                debug!("    sup (before): {:?}", sup_def.value);

                if !sup_def.constant {
                    // If this is not a constant, then grow the value as needed to
                    // accommodate the outlives constraint.

                    if dfs.copy(sub, &mut sup_def.value, constraint.point) {
                        changed = true;
                    }

                    debug!("    sup (after) : {:?}", sup_def.value);
                    debug!("    changed     : {:?}", changed);
                } else {
                    // If this is a constant, check whether it *would
                    // have* to grow in order for the constraint to be
                    // satisfied. If so, create an error.

                    let mut sup_value = sup_def.value.clone();
                    if dfs.copy(sub, &mut sup_value, constraint.point) {
                        // Constant values start out with the entire
                        // CFG, so it must be some new free region
                        // that was added. Find one.
                        let &new_region = sup_value
                            .free_regions
                            .difference(&sup_def.value.free_regions)
                            .next()
                            .unwrap();
                        debug!("    new_region : {:?}", new_region);
                        if error_regions.insert(constraint.sup) {
                            errors.push((constraint.sup, constraint.span, new_region));
                        }
                    }
                }
            }
            debug!("\n");
        }
        errors
    }
}

struct Dfs<'a, 'tcx: 'a> {
    mir: &'a Mir<'tcx>,
}

impl<'a, 'tcx> Dfs<'a, 'tcx> {
    fn new(mir: &'a Mir<'tcx>) -> Self {
        Self { mir }
    }

    fn copy(
        &mut self,
        from_region: &Region,
        to_region: &mut Region,
        start_point: Location,
    ) -> bool {
        let mut changed = false;

        let mut stack = vec![];
        let mut visited = FxHashSet();

        stack.push(start_point);
        while let Some(p) = stack.pop() {
            debug!("        dfs: p={:?}", p);

            if !from_region.contains_point(p) {
                debug!("            not in from-region");
                continue;
            }

            if !visited.insert(p) {
                debug!("            already visited");
                continue;
            }

            changed |= to_region.add_point(p);

            let block_data = &self.mir[p.block];
            let successor_points = if p.statement_index < block_data.statements.len() {
                vec![
                    Location {
                        statement_index: p.statement_index + 1,
                        ..p
                    },
                ]
            } else {
                block_data
                    .terminator()
                    .successors()
                    .iter()
                    .map(|&basic_block| {
                        Location {
                            statement_index: 0,
                            block: basic_block,
                        }
                    })
                    .collect::<Vec<_>>()
            };

            if successor_points.is_empty() {
                // If we reach the END point in the graph, then copy
                // over any skolemized end points in the `from_region`
                // and make sure they are included in the `to_region`.

                debug!("        dfs: free_regions={:?}", from_region.free_regions);
                for &fr in &from_region.free_regions {
                    changed |= to_region.free_regions.insert(fr);
                }
            } else {
                stack.extend(successor_points);
            }
        }

        changed
    }
}

impl<'tcx> RegionDefinition<'tcx> {
    fn new(origin: RegionVariableOrigin) -> Self {
        // Create a new region definition. Note that, for free
        // regions, these fields get updated later in
        // `init_free_regions`.
        Self {
            origin,
            name: None,
            constant: false,
            value: Region::default(),
        }
    }
}
<commit_msg>region_infer: improved debug logging<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::free_regions::FreeRegions;
use rustc::infer::InferCtxt;
use rustc::infer::RegionVariableOrigin;
use rustc::infer::NLLRegionVariableOrigin;
use rustc::infer::region_constraints::VarOrigins;
use rustc::mir::{Location, Mir};
use rustc::ty::{self, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashSet;
use std::collections::BTreeSet;
use std::fmt;
use syntax_pos::Span;

pub struct RegionInferenceContext<'tcx> {
    /// Contains the definition for every region variable.  Region
    /// variables are identified by their index (`RegionVid`). The
    /// definition contains information about where the region came
    /// from as well as its final inferred value.
    definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,

    /// The constraints we have accumulated and used during solving.
    constraints: Vec<Constraint>,
}

struct RegionDefinition<'tcx> {
    /// Why we created this variable. Mostly these will be
    /// `RegionVariableOrigin::NLL`, but some variables get created
    /// elsewhere in the code with other causes (e.g., instantiation
    /// late-bound-regions).
    origin: RegionVariableOrigin,

    /// If this is a free-region, then this is `Some(X)` where `X` is
    /// the name of the region.
    name: Option<ty::Region<'tcx>>,

    /// If true, this is a constant region which cannot grow larger.
    /// This is used for named regions as well as `'static`.
    constant: bool,

    /// The current value of this inference variable. This starts out
    /// empty, but grows as we add constraints. The final value is
    /// determined when `solve()` is executed.
    value: Region,
}

/// The value of an individual region variable. Region variables
/// consist of a set of points in the CFG as well as a set of "free
/// regions", which are sometimes written as `end(R)`. These
/// correspond to the named lifetimes and refer to portions of the
/// caller's control-flow graph -- specifically some portion that can
/// be reached after we return.
#[derive(Clone, Default, PartialEq, Eq)]
struct Region {
    points: BTreeSet<Location>,
    free_regions: BTreeSet<RegionVid>,
}

impl fmt::Debug for Region {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        formatter
            .debug_set()
            .entries(&self.points)
            .entries(&self.free_regions)
            .finish()
    }
}

impl Region {
    fn add_point(&mut self, point: Location) -> bool {
        self.points.insert(point)
    }

    fn add_free_region(&mut self, region: RegionVid) -> bool {
        self.free_regions.insert(region)
    }

    fn contains_point(&self, point: Location) -> bool {
        self.points.contains(&point)
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Constraint {
    // NB. The ordering here is not significant for correctness, but
    // it is for conenience. Before we dump the constraints in the
    // debugging logs, we sort them, and we'd like the "super region"
    // to be first, etc. (In particular, span should remain last.)

    /// The region SUP must outlive SUB...
    sup: RegionVid,

    /// Region that must be outlived.
    sub: RegionVid,

    /// At this location.
    point: Location,

    /// Where did this constraint arise?
    span: Span,
}

impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
    /// Creates a new region inference context with a total of
    /// `num_region_variables` valid inference variables; the first N
    /// of those will be constant regions representing the free
    /// regions defined in `free_regions`.
    pub fn new(var_origins: VarOrigins, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) -> Self {
        // Create a RegionDefinition for each inference variable.
        let definitions = var_origins
            .into_iter()
            .map(|origin| RegionDefinition::new(origin))
            .collect();

        let mut result = Self {
            definitions: definitions,
            constraints: Vec::new(),
        };

        result.init_free_regions(free_regions, mir);

        result
    }

    /// Initializes the region variables for each free region
    /// (lifetime parameter). The first N variables always correspond
    /// to the free regions appearing in the function signature (both
    /// named and anonymous) and where clauses. This function iterates
    /// over those regions and initializes them with minimum values.
    ///
    /// For example:
    ///
    ///     fn foo<'a, 'b>(..) where 'a: 'b
    ///
    /// would initialize two variables like so:
    ///
    ///     R0 = { CFG, R0 } // 'a
    ///     R1 = { CFG, R0, R1 } // 'b
    ///
    /// Here, R0 represents `'a`, and it contains (a) the entire CFG
    /// and (b) any free regions that it outlives, which in this case
    /// is just itself. R1 (`'b`) in contrast also outlives `'a` and
    /// hence contains R0 and R1.
    fn init_free_regions(&mut self, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) {
        let FreeRegions {
            indices,
            free_region_map,
        } = free_regions;

        // For each free region X:
        for (free_region, &variable) in indices {
            // These should be free-region variables.
            assert!(match self.definitions[variable].origin {
                RegionVariableOrigin::NLL(NLLRegionVariableOrigin::FreeRegion) => true,
                _ => false,
            });

            // Initialize the name and a few other details.
            self.definitions[variable].name = Some(free_region);
            self.definitions[variable].constant = true;

            // Add all nodes in the CFG to `definition.value`.
            for (block, block_data) in mir.basic_blocks().iter_enumerated() {
                let definition = &mut self.definitions[variable];
                for statement_index in 0..block_data.statements.len() + 1 {
                    let location = Location {
                        block,
                        statement_index,
                    };
                    definition.value.add_point(location);
                }
            }

            // Add `end(X)` into the set for X.
            self.definitions[variable].value.add_free_region(variable);

            // Go through each region Y that outlives X (i.e., where
            // Y: X is true). Add `end(X)` into the set for `Y`.
            for superregion in free_region_map.regions_that_outlive(&free_region) {
                let superregion_index = indices[superregion];
                self.definitions[superregion_index]
                    .value
                    .add_free_region(variable);
            }

            debug!(
                "init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`",
                free_region,
                variable,
                self.definitions[variable].value
            );
        }
    }

    /// Returns an iterator over all the region indices.
    pub fn regions(&self) -> impl Iterator<Item = RegionVid> {
        self.definitions.indices()
    }

    /// Returns true if the region `r` contains the point `p`.
    ///
    /// Until `solve()` executes, this value is not particularly meaningful.
    pub fn region_contains_point(&self, r: RegionVid, p: Location) -> bool {
        self.definitions[r].value.contains_point(p)
    }

    /// Returns access to the value of `r` for debugging purposes.
    pub(super) fn region_value(&self, r: RegionVid) -> &fmt::Debug {
        &self.definitions[r].value
    }

    /// Indicates that the region variable `v` is live at the point `point`.
    pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) {
        debug!("add_live_point({:?}, {:?})", v, point);
        let definition = &mut self.definitions[v];
        if !definition.constant {
            definition.value.add_point(point);
        } else {
            // Constants are used for free regions, which already
            // contain all the points in the control-flow graph.
            assert!(definition.value.contains_point(point));
        }
    }

    /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
    pub(super) fn add_outlives(
        &mut self,
        span: Span,
        sup: RegionVid,
        sub: RegionVid,
        point: Location,
    ) {
        debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
        self.constraints.push(Constraint {
            span,
            sup,
            sub,
            point,
        });
    }

    /// Perform region inference.
    pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
        let errors = self.propagate_constraints(mir);

        // worst error msg ever
        for (fr1, span, fr2) in errors {
            infcx.tcx.sess.span_err(
                span,
                &format!(
                    "free region `{}` does not outlive `{}`",
                    self.definitions[fr1].name.unwrap(),
                    self.definitions[fr2].name.unwrap()
                ),
            );
        }
    }

    /// Propagate the region constraints: this will grow the values
    /// for each region variable until all the constraints are
    /// satisfied. Note that some values may grow **too** large to be
    /// feasible, but we check this later.
    fn propagate_constraints(&mut self, mir: &Mir<'tcx>) -> Vec<(RegionVid, Span, RegionVid)> {
        let mut changed = true;
        let mut dfs = Dfs::new(mir);
        let mut error_regions = FxHashSet();
        let mut errors = vec![];

        debug!("propagate_constraints()");
        debug!("propagate_constraints: constraints={:#?}", {
            let mut constraints: Vec<_> = self.constraints.iter().collect();
            constraints.sort();
            constraints
        });

        while changed {
            changed = false;
            for constraint in &self.constraints {
                debug!("propagate_constraints: constraint={:?}", constraint);
                let sub = &self.definitions[constraint.sub].value.clone();
                let sup_def = &mut self.definitions[constraint.sup];

                debug!("propagate_constraints:    sub (before): {:?}", sub);
                debug!("propagate_constraints:    sup (before): {:?}", sup_def.value);

                if !sup_def.constant {
                    // If this is not a constant, then grow the value as needed to
                    // accommodate the outlives constraint.

                    if dfs.copy(sub, &mut sup_def.value, constraint.point) {
                        changed = true;
                    }

                    debug!("propagate_constraints:    sup (after) : {:?}", sup_def.value);
                    debug!("propagate_constraints:    changed     : {:?}", changed);
                } else {
                    // If this is a constant, check whether it *would
                    // have* to grow in order for the constraint to be
                    // satisfied. If so, create an error.

                    let mut sup_value = sup_def.value.clone();
                    if dfs.copy(sub, &mut sup_value, constraint.point) {
                        // Constant values start out with the entire
                        // CFG, so it must be some new free region
                        // that was added. Find one.
                        let &new_region = sup_value
                            .free_regions
                            .difference(&sup_def.value.free_regions)
                            .next()
                            .unwrap();
                        debug!("propagate_constraints:    new_region : {:?}", new_region);
                        if error_regions.insert(constraint.sup) {
                            errors.push((constraint.sup, constraint.span, new_region));
                        }
                    }
                }
            }
            debug!("\n");
        }
        errors
    }
}

struct Dfs<'a, 'tcx: 'a> {
    mir: &'a Mir<'tcx>,
}

impl<'a, 'tcx> Dfs<'a, 'tcx> {
    fn new(mir: &'a Mir<'tcx>) -> Self {
        Self { mir }
    }

    fn copy(
        &mut self,
        from_region: &Region,
        to_region: &mut Region,
        start_point: Location,
    ) -> bool {
        let mut changed = false;

        let mut stack = vec![];
        let mut visited = FxHashSet();

        stack.push(start_point);
        while let Some(p) = stack.pop() {
            debug!("        dfs: p={:?}", p);

            if !from_region.contains_point(p) {
                debug!("            not in from-region");
                continue;
            }

            if !visited.insert(p) {
                debug!("            already visited");
                continue;
            }

            changed |= to_region.add_point(p);

            let block_data = &self.mir[p.block];
            let successor_points = if p.statement_index < block_data.statements.len() {
                vec![
                    Location {
                        statement_index: p.statement_index + 1,
                        ..p
                    },
                ]
            } else {
                block_data
                    .terminator()
                    .successors()
                    .iter()
                    .map(|&basic_block| {
                        Location {
                            statement_index: 0,
                            block: basic_block,
                        }
                    })
                    .collect::<Vec<_>>()
            };

            if successor_points.is_empty() {
                // If we reach the END point in the graph, then copy
                // over any skolemized end points in the `from_region`
                // and make sure they are included in the `to_region`.

                debug!("        dfs: free_regions={:?}", from_region.free_regions);
                for &fr in &from_region.free_regions {
                    changed |= to_region.free_regions.insert(fr);
                }
            } else {
                stack.extend(successor_points);
            }
        }

        changed
    }
}

impl<'tcx> RegionDefinition<'tcx> {
    fn new(origin: RegionVariableOrigin) -> Self {
        // Create a new region definition. Note that, for free
        // regions, these fields get updated later in
        // `init_free_regions`.
        Self {
            origin,
            name: None,
            constant: false,
            value: Region::default(),
        }
    }
}

impl fmt::Debug for Constraint {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            formatter,
            "({:?}: {:?} @ {:?}) due to {:?}",
            self.sup,
            self.sub,
            self.point,
            self.span
        )
    }
}
<|endoftext|>


<commit_before>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code generation and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.

use std::env;

use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::pushd;
use xtask::{
    codegen::{self, Mode},
    dist::DistCmd,
    install::{InstallCmd, Malloc, ServerOpt},
    metrics::MetricsCmd,
    pre_cache::PreCacheCmd,
    pre_commit, project_root,
    release::{PromoteCmd, ReleaseCmd},
    run_clippy, run_fuzzer, run_rustfmt, Result,
};

fn main() -> Result<()> {
    if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
        return pre_commit::run_hook();
    }

    let _d = pushd(project_root())?;

    let mut args = Arguments::from_env();
    let subcommand = args.subcommand()?.unwrap_or_default();

    match subcommand.as_str() {
        "install" => {
            if args.contains(["-h", "--help"]) {
                eprintln!(
                    "\
cargo xtask install
Install rust-analyzer server or editor plugin.

USAGE:
    cargo xtask install [FLAGS]

FLAGS:
        --client-code[=CLIENT]    Install only VS Code plugin.
                                  CLIENT is one of 'code', 'code-insiders', 'codium', or 'code-oss'
        --server                  Install only the language server
        --mimalloc                Use mimalloc for server
    -h, --help                    Prints help information
        "
                );
                return Ok(());
            }
            let server = args.contains("--server");
            let client_code = args.contains("--client-code");
            if server && client_code {
                eprintln!(
                    "error: The argument `--server` cannot be used with `--client-code`\n\n\
                     For more information try --help"
                );
                return Ok(());
            }

            let malloc =
                if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };

            let client_opt = args.opt_value_from_str("--client-code")?;

            args.finish()?;

            InstallCmd {
                client: if server { None } else { Some(client_opt.unwrap_or_default()) },
                server: if client_code { None } else { Some(ServerOpt { malloc }) },
            }
            .run()
        }
        "codegen" => {
            let features = args.contains("--features");
            args.finish()?;
            CodegenCmd { features }.run()
        }
        "format" => {
            args.finish()?;
            run_rustfmt(Mode::Overwrite)
        }
        "install-pre-commit-hook" => {
            args.finish()?;
            pre_commit::install_hook()
        }
        "lint" => {
            args.finish()?;
            run_clippy()
        }
        "fuzz-tests" => {
            args.finish()?;
            run_fuzzer()
        }
        "pre-cache" => {
            args.finish()?;
            PreCacheCmd.run()
        }
        "release" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            ReleaseCmd { dry_run }.run()
        }
        "promote" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            PromoteCmd { dry_run }.run()
        }
        "dist" => {
            let nightly = args.contains("--nightly");
            let client_version: Option<String> = args.opt_value_from_str("--client")?;
            args.finish()?;
            DistCmd { nightly, client_version }.run()
        }
        "metrics" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            MetricsCmd { dry_run }.run()
        }
        _ => {
            eprintln!(
                "\
cargo xtask
Run custom build command.

USAGE:
    cargo xtask <SUBCOMMAND>

SUBCOMMANDS:
    format
    install-pre-commit-hook
    fuzz-tests
    codegen
    install
    lint
    dist
    promote"
            );
            Ok(())
        }
    }
}
<commit_msg>rename flag --client-code to --client on xtask install<commit_after>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code generation and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.

use std::env;

use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::pushd;
use xtask::{
    codegen::{self, Mode},
    dist::DistCmd,
    install::{InstallCmd, Malloc, ServerOpt},
    metrics::MetricsCmd,
    pre_cache::PreCacheCmd,
    pre_commit, project_root,
    release::{PromoteCmd, ReleaseCmd},
    run_clippy, run_fuzzer, run_rustfmt, Result,
};

fn main() -> Result<()> {
    if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
        return pre_commit::run_hook();
    }

    let _d = pushd(project_root())?;

    let mut args = Arguments::from_env();
    let subcommand = args.subcommand()?.unwrap_or_default();

    match subcommand.as_str() {
        "install" => {
            if args.contains(["-h", "--help"]) {
                eprintln!(
                    "\
cargo xtask install
Install rust-analyzer server or editor plugin.

USAGE:
    cargo xtask install [FLAGS]

FLAGS:
        --client[=CLIENT] Install only VS Code plugin.
                          CLIENT is one of 'code', 'code-insiders', 'codium', or 'code-oss'
        --server          Install only the language server
        --mimalloc        Use mimalloc for server
    -h, --help            Prints help information
        "
                );
                return Ok(());
            }
            let server = args.contains("--server");
            let client_code = args.contains("--client");
            if server && client_code {
                eprintln!(
                    "error: The argument `--server` cannot be used with `--client`\n\n\
                     For more information try --help"
                );
                return Ok(());
            }

            let malloc =
                if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };

            let client_opt = args.opt_value_from_str("--client")?;

            args.finish()?;

            InstallCmd {
                client: if server { None } else { Some(client_opt.unwrap_or_default()) },
                server: if client_code { None } else { Some(ServerOpt { malloc }) },
            }
            .run()
        }
        "codegen" => {
            let features = args.contains("--features");
            args.finish()?;
            CodegenCmd { features }.run()
        }
        "format" => {
            args.finish()?;
            run_rustfmt(Mode::Overwrite)
        }
        "install-pre-commit-hook" => {
            args.finish()?;
            pre_commit::install_hook()
        }
        "lint" => {
            args.finish()?;
            run_clippy()
        }
        "fuzz-tests" => {
            args.finish()?;
            run_fuzzer()
        }
        "pre-cache" => {
            args.finish()?;
            PreCacheCmd.run()
        }
        "release" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            ReleaseCmd { dry_run }.run()
        }
        "promote" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            PromoteCmd { dry_run }.run()
        }
        "dist" => {
            let nightly = args.contains("--nightly");
            let client_version: Option<String> = args.opt_value_from_str("--client")?;
            args.finish()?;
            DistCmd { nightly, client_version }.run()
        }
        "metrics" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            MetricsCmd { dry_run }.run()
        }
        _ => {
            eprintln!(
                "\
cargo xtask
Run custom build command.

USAGE:
    cargo xtask <SUBCOMMAND>

SUBCOMMANDS:
    format
    install-pre-commit-hook
    fuzz-tests
    codegen
    install
    lint
    dist
    promote"
            );
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{
    FloatRegisters,
    IntRegisters,
    data,
    error,
    flag,
    io,
    number,
    ptrace_event,
    scheme,
};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b, c),
                        SYS_FMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated fmap(...) call", core::str::from_utf8(&name));
                            }
                            file_op(a, fd, c, d)
                        },
                        SYS_FUNMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated funmap(...) call", core::str::from_utf8(&name));
                            }
                            funmap_old(b)
                        },
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => {
                    let b = CloneFlags::from_bits_truncate(b);

                    #[cfg(target_arch = "aarch64")]
                    {
                        //TODO: CLONE_STACK
                        clone(b, bp).map(ContextId::into)
                    }

                    #[cfg(target_arch = "x86_64")]
                    {
                        let old_rsp = stack.iret.rsp;
                        if b.contains(flag::CLONE_STACK) {
                            stack.iret.rsp = c;
                        }
                        let ret = clone(b, bp).map(ContextId::into);
                        stack.iret.rsp = old_rsp;
                        ret
                    }
                },
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { core::str::from_utf8_unchecked(&name_raw) };
            if name.contains("redoxfs") {
                if a == SYS_CLOCK_GETTIME || a == SYS_YIELD {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }
    */

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, bp, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    /*
    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }
    */

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<commit_msg>aarch64: clone: Return from clone syscall<commit_after>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{
    FloatRegisters,
    IntRegisters,
    data,
    error,
    flag,
    io,
    number,
    ptrace_event,
    scheme,
};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b, c),
                        SYS_FMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated fmap(...) call", core::str::from_utf8(&name));
                            }
                            file_op(a, fd, c, d)
                        },
                        SYS_FUNMAP_OLD => {
                            {
                                let contexts = crate::context::contexts();
                                let current = contexts.current().unwrap();
                                let current = current.read();
                                let name = current.name.lock();
                                println!("{:?} using deprecated funmap(...) call", core::str::from_utf8(&name));
                            }
                            funmap_old(b)
                        },
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => {
                    let b = CloneFlags::from_bits_truncate(b);

                    #[cfg(target_arch = "aarch64")]
                    {
                        //TODO: CLONE_STACK
                        let ret = clone(b, bp).map(ContextId::into);
                        ret
                    }

                    #[cfg(target_arch = "x86_64")]
                    {
                        let old_rsp = stack.iret.rsp;
                        if b.contains(flag::CLONE_STACK) {
                            stack.iret.rsp = c;
                        }
                        let ret = clone(b, bp).map(ContextId::into);
                        stack.iret.rsp = old_rsp;
                        ret
                    }
                },
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { core::str::from_utf8_unchecked(&name_raw) };
            if name.contains("redoxfs") {
                if a == SYS_CLOCK_GETTIME || a == SYS_YIELD {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }
    */

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, bp, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    /*
    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }
    */

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Servo's experimental layout system builds a tree of `FlowContext` and `RenderBox` objects and
/// solves layout constraints to obtain positions and display attributes of tree nodes. Positions
/// are computed in several tree traversals driven by the fundamental data dependencies required by
/// inline and block layout.
///
/// Flows are interior nodes in the layout tree and correspond closely to *flow contexts* in the
/// CSS specification. Flows are responsible for positioning their child flow contexts and render
/// boxes. Flows have purpose-specific fields, such as auxiliary line box structs, out-of-flow
/// child lists, and so on.
///
/// Currently, the important types of flows are:
///
/// * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of
///   which are positioned according to block formatting context rules (CSS block boxes). Block
///   flows also contain a single `GenericBox` to represent their rendered borders, padding, etc.
///   (In the future, this render box may be folded into `BlockFlow` to save space.) The BlockFlow
///   at the root of the tree has special behavior: it stretches to the boundaries of the viewport.
///
/// * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child
///   boxes/flows that are subject to inline layout and line breaking and structs to represent
///   line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and
///   similar methods.

use layout::block::BlockFlowData;
use layout::float::FloatFlowData;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::inline::{InlineFlowData};
use layout::float_context::{FloatContext, Invalid, FloatType};

use std::cell::Cell;
use std::uint;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use script::dom::node::{AbstractNode, LayoutView};
use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils};

/// The type of the formatting context and data specific to each context, such as line box
/// structures or float lists.
pub enum FlowContext {
    AbsoluteFlow(@mut FlowData),
    BlockFlow(@mut BlockFlowData),
    FloatFlow(@mut FloatFlowData),
    InlineBlockFlow(@mut FlowData),
    InlineFlow(@mut InlineFlowData),
    TableFlow(@mut FlowData),
}

pub enum FlowContextType {
    Flow_Absolute,
    Flow_Block,
    Flow_Float(FloatType),
    Flow_InlineBlock,
    Flow_Inline,
    Flow_Root,
    Flow_Table
}

impl Clone for FlowContext {
    fn clone(&self) -> FlowContext {
        *self
    }
}

impl FlowContext {
    pub fn teardown(&self) {
        match *self {
          AbsoluteFlow(data) |
          InlineBlockFlow(data) |
          TableFlow(data) => data.teardown(),
          BlockFlow(data) => data.teardown(),
          FloatFlow(data) => data.teardown(),
          InlineFlow(data) => data.teardown()
        }
    }

    /// Like traverse_preorder, but don't end the whole traversal if the callback
    /// returns false.
    fn partially_traverse_preorder(&self, callback: &fn(FlowContext) -> bool) {
        if !callback((*self).clone()) {
            return;
        }

        for self.each_child |kid| {
            // FIXME: Work around rust#2202. We should be able to pass the callback directly.
            kid.partially_traverse_preorder(|a| callback(a));
        }
    }
}

impl FlowData {
    pub fn teardown(&mut self) {
        // Under the assumption that all flows exist in a tree,
        // we must restrict ourselves to finalizing flows that
        // are descendents and subsequent siblings to ourselves,
        // or we risk dynamic borrow failures.
        self.parent = None;

        for self.first_child.iter().advance |flow| {
            flow.teardown();
        }
        self.first_child = None;

        self.last_child = None;

        for self.next_sibling.iter().advance |flow| {
            flow.teardown();
        }
        self.next_sibling = None;

        self.prev_sibling = None;
    }
}

impl TreeNodeRef<FlowData> for FlowContext {
    fn with_base<R>(&self, callback: &fn(&FlowData) -> R) -> R {
        match *self {
            AbsoluteFlow(info) => callback(info),
            BlockFlow(info) => {
                callback(&info.common)
            }
            FloatFlow(info) => callback(&info.common),
            InlineBlockFlow(info) => callback(info),
            InlineFlow(info) => {
                callback(&info.common)
            }
            TableFlow(info) => callback(info)
        }
    }
    fn with_mut_base<R>(&self, callback: &fn(&mut FlowData) -> R) -> R {
        match *self {
            AbsoluteFlow(info) => callback(info),
            BlockFlow(info) => {
                callback(&mut info.common)
            }
            FloatFlow(info) => callback(&mut info.common),
            InlineBlockFlow(info) => callback(info),
            InlineFlow(info) => {
                callback(&mut info.common)
            }
            TableFlow(info) => callback(info),
        }
    }
}

/// Data common to all flows.
///
/// FIXME: We need a naming convention for pseudo-inheritance like this. How about
/// `CommonFlowInfo`?
pub struct FlowData {
    node: AbstractNode<LayoutView>,

    parent: Option<FlowContext>,
    first_child: Option<FlowContext>,
    last_child: Option<FlowContext>,
    prev_sibling: Option<FlowContext>,
    next_sibling: Option<FlowContext>,

    /* TODO (Issue #87): debug only */
    id: int,

    /* layout computations */
    // TODO: min/pref and position are used during disjoint phases of
    // layout; maybe combine into a single enum to save space.
    min_width: Au,
    pref_width: Au,
    position: Rect<Au>,
    floats_in: FloatContext,
    floats_out: FloatContext,
    num_floats: uint,
    abs_position: Point2D<Au>
}

impl TreeNode<FlowContext> for FlowData {
    fn parent_node(&self) -> Option<FlowContext> {
        self.parent
    }

    fn first_child(&self) -> Option<FlowContext> {
        self.first_child
    }

    fn last_child(&self) -> Option<FlowContext> {
        self.last_child
    }

    fn prev_sibling(&self) -> Option<FlowContext> {
        self.prev_sibling
    }

    fn next_sibling(&self) -> Option<FlowContext> {
        self.next_sibling
    }

    fn set_parent_node(&mut self, new_parent_node: Option<FlowContext>) {
        self.parent = new_parent_node
    }

    fn set_first_child(&mut self, new_first_child: Option<FlowContext>) {
        self.first_child = new_first_child
    }

    fn set_last_child(&mut self, new_last_child: Option<FlowContext>) {
        self.last_child = new_last_child
    }

    fn set_prev_sibling(&mut self, new_prev_sibling: Option<FlowContext>) {
        self.prev_sibling = new_prev_sibling
    }

    fn set_next_sibling(&mut self, new_next_sibling: Option<FlowContext>) {
        self.next_sibling = new_next_sibling
    }
}

impl FlowData {
    pub fn new(id: int, node: AbstractNode<LayoutView>) -> FlowData {
        FlowData {
            node: node,

            parent: None,
            first_child: None,
            last_child: None,
            prev_sibling: None,
            next_sibling: None,

            id: id,

            min_width: Au(0),
            pref_width: Au(0),
            position: Au::zero_rect(),
            floats_in: Invalid,
            floats_out: Invalid,
            num_floats: 0,
            abs_position: Point2D(Au(0), Au(0))
        }
    }
}

impl<'self> FlowContext {
    /// A convenience method to return the position of this flow. Fails if the flow is currently
    /// being borrowed mutably.
    #[inline(always)]
    pub fn position(&self) -> Rect<Au> {
        do self.with_base |common_info| {
            common_info.position
        }
    }

    /// A convenience method to return the ID of this flow. Fails if the flow is currently being
    /// borrowed mutably.
    #[inline(always)]
    pub fn id(&self) -> int {
        do self.with_base |info| {
            info.id
        }
    }

    pub fn inline(&self) -> @mut InlineFlowData {
        match *self {
            InlineFlow(info) => info,
            _ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.id()))
        }
    }

    pub fn block(&self) -> @mut BlockFlowData {
        match *self {
            BlockFlow(info) => info,
            _ => fail!(fmt!("Tried to access block data of non-block: f%d", self.id()))
        }
    }

    pub fn root(&self) -> @mut BlockFlowData {
        match *self {
            BlockFlow(info) if info.is_root => info,
            _ => fail!(fmt!("Tried to access root block data of non-root: f%d", self.id()))
        }
    }

    pub fn bubble_widths(&self, ctx: &mut LayoutContext) {
        match *self {
            BlockFlow(info)  => info.bubble_widths_block(ctx),
            InlineFlow(info) => info.bubble_widths_inline(ctx),
            FloatFlow(info)  => info.bubble_widths_float(ctx),
            _ => fail!(fmt!("Tried to bubble_widths of flow: f%d", self.id()))
        }
    }

    pub fn assign_widths(&self, ctx: &mut LayoutContext) {
        match *self {
            BlockFlow(info)  => info.assign_widths_block(ctx),
            InlineFlow(info) => info.assign_widths_inline(ctx),
            FloatFlow(info)  => info.assign_widths_float(ctx),
            _ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
        }
    }

    pub fn assign_height(&self, ctx: &mut LayoutContext) {
        match *self {
            BlockFlow(info)  => info.assign_height_block(ctx),
            InlineFlow(info) => info.assign_height_inline(ctx),
            FloatFlow(info)  => info.assign_height_float(ctx),
            _ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
        }
    }

    pub fn build_display_list<E:ExtraDisplayListData>(&self,
                                                     builder: &DisplayListBuilder,
                                                     dirty: &Rect<Au>,
                                                     list: &Cell<DisplayList<E>>)
                                                     -> bool {

        match *self {
            BlockFlow(info)  => info.build_display_list_block(builder, dirty, list),
            InlineFlow(info) => info.build_display_list_inline(builder, dirty, list),
            FloatFlow(info)  => info.build_display_list_float(builder, dirty, list),
            _ => {
                fail!("Tried to build_display_list_recurse of flow: %?", self)
            }
        }

    }

    // Actual methods that do not require much flow-specific logic
    pub fn foldl_all_boxes<B:Clone>(&self, seed: B, cb: &fn(a: B, b: RenderBox) -> B) -> B {
        match *self {
            BlockFlow(block) => {
                let block = &mut *block;
                do block.box.map_default(seed.clone()) |box| {
                    cb(seed.clone(), *box)
                }
            }
            InlineFlow(inline) => {
                let inline = &mut *inline;
                do inline.boxes.iter().fold(seed) |acc, box| {
                    cb(acc.clone(), *box)
                }
            }
            _ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self)),
        }
    }

    pub fn foldl_boxes_for_node<B:Clone>(&self,
                                        node: AbstractNode<LayoutView>,
                                        seed: B,
                                        callback: &fn(a: B, RenderBox) -> B)
                                        -> B {
        do self.foldl_all_boxes(seed) |acc, box| {
            if box.node() == node {
                callback(acc, box)
            } else {
                acc
            }
        }
    }

    pub fn iter_all_boxes(&self, cb: &fn(RenderBox) -> bool) -> bool {
        match *self {
            BlockFlow(block) => {
                let block = &mut *block;
                for block.box.iter().advance |box| {
                    if !cb(*box) {
                        break;
                    }
                }
            }
            InlineFlow(inline) => {
                let inline = &mut *inline;
                for inline.boxes.iter().advance |box| {
                    if !cb(*box) {
                        break;
                    }
                }
            }
            _ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self))
        }

        true
    }

    pub fn iter_boxes_for_node(&self,
                               node: AbstractNode<LayoutView>,
                               callback: &fn(RenderBox) -> bool)
                               -> bool {
        for self.iter_all_boxes |box| {
            if box.node() == node {
                if !callback(box) {
                    break;
                }
            }
        }

        true
    }

    /// Dumps the flow tree for debugging.
    pub fn dump(&self) {
        self.dump_indent(0);
    }

    /// Dumps the flow tree, for debugging, with indentation.
    pub fn dump_indent(&self, indent: uint) {
        let mut s = ~"|";
        for uint::range(0, indent) |_i| {
            s.push_str("---- ");
        }

        s.push_str(self.debug_str());
        println(s);

        // FIXME: this should have a pure/const version?
        for self.each_child |child| {
            child.dump_indent(indent + 1)
        }
    }

    pub fn debug_str(&self) -> ~str {
        let repr = match *self {
            InlineFlow(inline) => {
                let mut s = inline.boxes.iter().fold(~"InlineFlow(children=", |s, box| {
                    fmt!("%s b%d", s, box.id())
                });
                s.push_str(")");
                s
            },
            BlockFlow(block) => {
                match block.box {
                    Some(box) => fmt!("BlockFlow(box=b%d)", box.id()),
                    None => ~"BlockFlow",
                }
            },
            FloatFlow(float) => {
                match float.box {
                    Some(box) => fmt!("FloatFlow(box=b%d)", box.id()),
                    None => ~"FloatFlow",
                }
            },
            _ => ~"(Unknown flow)"
        };

        do self.with_base |base| {
            fmt!("f%? %? floats %? size %?", base.id, repr, base.num_floats, base.position)
        }
    }
}

<commit_msg>debug: Send flow tree dump to stderr for consistency<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Servo's experimental layout system builds a tree of `FlowContext` and `RenderBox` objects and
/// solves layout constraints to obtain positions and display attributes of tree nodes. Positions
/// are computed in several tree traversals driven by the fundamental data dependencies required by
/// inline and block layout.
///
/// Flows are interior nodes in the layout tree and correspond closely to *flow contexts* in the
/// CSS specification. Flows are responsible for positioning their child flow contexts and render
/// boxes. Flows have purpose-specific fields, such as auxiliary line box structs, out-of-flow
/// child lists, and so on.
///
/// Currently, the important types of flows are:
///
/// * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of
///   which are positioned according to block formatting context rules (CSS block boxes). Block
///   flows also contain a single `GenericBox` to represent their rendered borders, padding, etc.
///   (In the future, this render box may be folded into `BlockFlow` to save space.) The BlockFlow
///   at the root of the tree has special behavior: it stretches to the boundaries of the viewport.
///
/// * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child
///   boxes/flows that are subject to inline layout and line breaking and structs to represent
///   line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and
///   similar methods.

use layout::block::BlockFlowData;
use layout::float::FloatFlowData;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::inline::{InlineFlowData};
use layout::float_context::{FloatContext, Invalid, FloatType};

use std::cell::Cell;
use std::uint;
use std::io::stderr;
use geom::point::Point2D;
use geom::rect::Rect;
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use script::dom::node::{AbstractNode, LayoutView};
use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils};

/// The type of the formatting context and data specific to each context, such as line box
/// structures or float lists.
pub enum FlowContext {
    AbsoluteFlow(@mut FlowData),
    BlockFlow(@mut BlockFlowData),
    FloatFlow(@mut FloatFlowData),
    InlineBlockFlow(@mut FlowData),
    InlineFlow(@mut InlineFlowData),
    TableFlow(@mut FlowData),
}

pub enum FlowContextType {
    Flow_Absolute,
    Flow_Block,
    Flow_Float(FloatType),
    Flow_InlineBlock,
    Flow_Inline,
    Flow_Root,
    Flow_Table
}

impl Clone for FlowContext {
    fn clone(&self) -> FlowContext {
        *self
    }
}

impl FlowContext {
    pub fn teardown(&self) {
        match *self {
          AbsoluteFlow(data) |
          InlineBlockFlow(data) |
          TableFlow(data) => data.teardown(),
          BlockFlow(data) => data.teardown(),
          FloatFlow(data) => data.teardown(),
          InlineFlow(data) => data.teardown()
        }
    }

    /// Like traverse_preorder, but don't end the whole traversal if the callback
    /// returns false.
    fn partially_traverse_preorder(&self, callback: &fn(FlowContext) -> bool) {
        if !callback((*self).clone()) {
            return;
        }

        for self.each_child |kid| {
            // FIXME: Work around rust#2202. We should be able to pass the callback directly.
            kid.partially_traverse_preorder(|a| callback(a));
        }
    }
}

impl FlowData {
    pub fn teardown(&mut self) {
        // Under the assumption that all flows exist in a tree,
        // we must restrict ourselves to finalizing flows that
        // are descendents and subsequent siblings to ourselves,
        // or we risk dynamic borrow failures.
        self.parent = None;

        for self.first_child.iter().advance |flow| {
            flow.teardown();
        }
        self.first_child = None;

        self.last_child = None;

        for self.next_sibling.iter().advance |flow| {
            flow.teardown();
        }
        self.next_sibling = None;

        self.prev_sibling = None;
    }
}

impl TreeNodeRef<FlowData> for FlowContext {
    fn with_base<R>(&self, callback: &fn(&FlowData) -> R) -> R {
        match *self {
            AbsoluteFlow(info) => callback(info),
            BlockFlow(info) => {
                callback(&info.common)
            }
            FloatFlow(info) => callback(&info.common),
            InlineBlockFlow(info) => callback(info),
            InlineFlow(info) => {
                callback(&info.common)
            }
            TableFlow(info) => callback(info)
        }
    }
    fn with_mut_base<R>(&self, callback: &fn(&mut FlowData) -> R) -> R {
        match *self {
            AbsoluteFlow(info) => callback(info),
            BlockFlow(info) => {
                callback(&mut info.common)
            }
            FloatFlow(info) => callback(&mut info.common),
            InlineBlockFlow(info) => callback(info),
            InlineFlow(info) => {
                callback(&mut info.common)
            }
            TableFlow(info) => callback(info),
        }
    }
}

/// Data common to all flows.
///
/// FIXME: We need a naming convention for pseudo-inheritance like this. How about
/// `CommonFlowInfo`?
pub struct FlowData {
    node: AbstractNode<LayoutView>,

    parent: Option<FlowContext>,
    first_child: Option<FlowContext>,
    last_child: Option<FlowContext>,
    prev_sibling: Option<FlowContext>,
    next_sibling: Option<FlowContext>,

    /* TODO (Issue #87): debug only */
    id: int,

    /* layout computations */
    // TODO: min/pref and position are used during disjoint phases of
    // layout; maybe combine into a single enum to save space.
    min_width: Au,
    pref_width: Au,
    position: Rect<Au>,
    floats_in: FloatContext,
    floats_out: FloatContext,
    num_floats: uint,
    abs_position: Point2D<Au>
}

impl TreeNode<FlowContext> for FlowData {
    fn parent_node(&self) -> Option<FlowContext> {
        self.parent
    }

    fn first_child(&self) -> Option<FlowContext> {
        self.first_child
    }

    fn last_child(&self) -> Option<FlowContext> {
        self.last_child
    }

    fn prev_sibling(&self) -> Option<FlowContext> {
        self.prev_sibling
    }

    fn next_sibling(&self) -> Option<FlowContext> {
        self.next_sibling
    }

    fn set_parent_node(&mut self, new_parent_node: Option<FlowContext>) {
        self.parent = new_parent_node
    }

    fn set_first_child(&mut self, new_first_child: Option<FlowContext>) {
        self.first_child = new_first_child
    }

    fn set_last_child(&mut self, new_last_child: Option<FlowContext>) {
        self.last_child = new_last_child
    }

    fn set_prev_sibling(&mut self, new_prev_sibling: Option<FlowContext>) {
        self.prev_sibling = new_prev_sibling
    }

    fn set_next_sibling(&mut self, new_next_sibling: Option<FlowContext>) {
        self.next_sibling = new_next_sibling
    }
}

impl FlowData {
    pub fn new(id: int, node: AbstractNode<LayoutView>) -> FlowData {
        FlowData {
            node: node,

            parent: None,
            first_child: None,
            last_child: None,
            prev_sibling: None,
            next_sibling: None,

            id: id,

            min_width: Au(0),
            pref_width: Au(0),
            position: Au::zero_rect(),
            floats_in: Invalid,
            floats_out: Invalid,
            num_floats: 0,
            abs_position: Point2D(Au(0), Au(0))
        }
    }
}

impl<'self> FlowContext {
    /// A convenience method to return the position of this flow. Fails if the flow is currently
    /// being borrowed mutably.
    #[inline(always)]
    pub fn position(&self) -> Rect<Au> {
        do self.with_base |common_info| {
            common_info.position
        }
    }

    /// A convenience method to return the ID of this flow. Fails if the flow is currently being
    /// borrowed mutably.
    #[inline(always)]
    pub fn id(&self) -> int {
        do self.with_base |info| {
            info.id
        }
    }

    pub fn inline(&self) -> @mut InlineFlowData {
        match *self {
            InlineFlow(info) => info,
            _ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.id()))
        }
    }

    pub fn block(&self) -> @mut BlockFlowData {
        match *self {
            BlockFlow(info) => info,
            _ => fail!(fmt!("Tried to access block data of non-block: f%d", self.id()))
        }
    }

    pub fn root(&self) -> @mut BlockFlowData {
        match *self {
            BlockFlow(info) if info.is_root => info,
            _ => fail!(fmt!("Tried to access root block data of non-root: f%d", self.id()))
        }
    }

    pub fn bubble_widths(&self, ctx: &mut LayoutContext) {
        match *self {
            BlockFlow(info)  => info.bubble_widths_block(ctx),
            InlineFlow(info) => info.bubble_widths_inline(ctx),
            FloatFlow(info)  => info.bubble_widths_float(ctx),
            _ => fail!(fmt!("Tried to bubble_widths of flow: f%d", self.id()))
        }
    }

    pub fn assign_widths(&self, ctx: &mut LayoutContext) {
        match *self {
            BlockFlow(info)  => info.assign_widths_block(ctx),
            InlineFlow(info) => info.assign_widths_inline(ctx),
            FloatFlow(info)  => info.assign_widths_float(ctx),
            _ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
        }
    }

    pub fn assign_height(&self, ctx: &mut LayoutContext) {
        match *self {
            BlockFlow(info)  => info.assign_height_block(ctx),
            InlineFlow(info) => info.assign_height_inline(ctx),
            FloatFlow(info)  => info.assign_height_float(ctx),
            _ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
        }
    }

    pub fn build_display_list<E:ExtraDisplayListData>(&self,
                                                     builder: &DisplayListBuilder,
                                                     dirty: &Rect<Au>,
                                                     list: &Cell<DisplayList<E>>)
                                                     -> bool {

        match *self {
            BlockFlow(info)  => info.build_display_list_block(builder, dirty, list),
            InlineFlow(info) => info.build_display_list_inline(builder, dirty, list),
            FloatFlow(info)  => info.build_display_list_float(builder, dirty, list),
            _ => {
                fail!("Tried to build_display_list_recurse of flow: %?", self)
            }
        }

    }

    // Actual methods that do not require much flow-specific logic
    pub fn foldl_all_boxes<B:Clone>(&self, seed: B, cb: &fn(a: B, b: RenderBox) -> B) -> B {
        match *self {
            BlockFlow(block) => {
                let block = &mut *block;
                do block.box.map_default(seed.clone()) |box| {
                    cb(seed.clone(), *box)
                }
            }
            InlineFlow(inline) => {
                let inline = &mut *inline;
                do inline.boxes.iter().fold(seed) |acc, box| {
                    cb(acc.clone(), *box)
                }
            }
            _ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self)),
        }
    }

    pub fn foldl_boxes_for_node<B:Clone>(&self,
                                        node: AbstractNode<LayoutView>,
                                        seed: B,
                                        callback: &fn(a: B, RenderBox) -> B)
                                        -> B {
        do self.foldl_all_boxes(seed) |acc, box| {
            if box.node() == node {
                callback(acc, box)
            } else {
                acc
            }
        }
    }

    pub fn iter_all_boxes(&self, cb: &fn(RenderBox) -> bool) -> bool {
        match *self {
            BlockFlow(block) => {
                let block = &mut *block;
                for block.box.iter().advance |box| {
                    if !cb(*box) {
                        break;
                    }
                }
            }
            InlineFlow(inline) => {
                let inline = &mut *inline;
                for inline.boxes.iter().advance |box| {
                    if !cb(*box) {
                        break;
                    }
                }
            }
            _ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self))
        }

        true
    }

    pub fn iter_boxes_for_node(&self,
                               node: AbstractNode<LayoutView>,
                               callback: &fn(RenderBox) -> bool)
                               -> bool {
        for self.iter_all_boxes |box| {
            if box.node() == node {
                if !callback(box) {
                    break;
                }
            }
        }

        true
    }

    /// Dumps the flow tree for debugging.
    pub fn dump(&self) {
        self.dump_indent(0);
    }

    /// Dumps the flow tree, for debugging, with indentation.
    pub fn dump_indent(&self, indent: uint) {
        let mut s = ~"|";
        for uint::range(0, indent) |_i| {
            s.push_str("---- ");
        }

        s.push_str(self.debug_str());
        stderr().write_line(s);

        // FIXME: this should have a pure/const version?
        for self.each_child |child| {
            child.dump_indent(indent + 1)
        }
    }

    pub fn debug_str(&self) -> ~str {
        let repr = match *self {
            InlineFlow(inline) => {
                let mut s = inline.boxes.iter().fold(~"InlineFlow(children=", |s, box| {
                    fmt!("%s b%d", s, box.id())
                });
                s.push_str(")");
                s
            },
            BlockFlow(block) => {
                match block.box {
                    Some(box) => fmt!("BlockFlow(box=b%d)", box.id()),
                    None => ~"BlockFlow",
                }
            },
            FloatFlow(float) => {
                match float.box {
                    Some(box) => fmt!("FloatFlow(box=b%d)", box.id()),
                    None => ~"FloatFlow",
                }
            },
            _ => ~"(Unknown flow)"
        };

        do self.with_base |base| {
            fmt!("f%? %? floats %? size %?", base.id, repr, base.num_floats, base.position)
        }
    }
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::EventBinding;
use dom::bindings::codegen::EventBinding::EventConstants;
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::Fallible;
use dom::eventtarget::EventTarget;
use dom::window::Window;
use servo_util::str::DOMString;

use geom::point::Point2D;

pub enum Event_ {
    ResizeEvent(uint, uint),
    ReflowEvent,
    ClickEvent(uint, Point2D<f32>),
    MouseDownEvent(uint, Point2D<f32>),
    MouseUpEvent(uint, Point2D<f32>),
    MouseMoveEvent(Point2D<f32>)
}

#[deriving(Encodable)]
pub enum EventPhase {
    PhaseNone      = EventConstants::NONE,
    PhaseCapturing = EventConstants::CAPTURING_PHASE,
    PhaseAtTarget  = EventConstants::AT_TARGET,
    PhaseBubbling  = EventConstants::BUBBLING_PHASE,
}

#[deriving(Eq, Encodable)]
pub enum EventTypeId {
    HTMLEventTypeId,
    UIEventTypeId,
    MouseEventTypeId,
    KeyEventTypeId
}

#[deriving(Encodable)]
pub struct Event {
    type_id: EventTypeId,
    reflector_: Reflector,
    current_target: Option<JS<EventTarget>>,
    target: Option<JS<EventTarget>>,
    type_: DOMString,
    phase: EventPhase,
    canceled: bool,
    stop_propagation: bool,
    stop_immediate: bool,
    cancelable: bool,
    bubbles: bool,
    trusted: bool,
    dispatching: bool,
    initialized: bool,
}

impl Event {
    pub fn new_inherited(type_id: EventTypeId) -> Event {
        Event {
            type_id: type_id,
            reflector_: Reflector::new(),
            current_target: None,
            target: None,
            phase: PhaseNone,
            type_: ~"",
            canceled: false,
            cancelable: true,
            bubbles: true,
            trusted: false,
            dispatching: false,
            stop_propagation: false,
            stop_immediate: false,
            initialized: false,
        }
    }

    pub fn new(window: &JS<Window>) -> JS<Event> {
        reflect_dom_object(~Event::new_inherited(HTMLEventTypeId),
                           window,
                           EventBinding::Wrap)
    }

    pub fn EventPhase(&self) -> u16 {
        self.phase as u16
    }

    pub fn Type(&self) -> DOMString {
        self.type_.clone()
    }

    pub fn GetTarget(&self) -> Option<JS<EventTarget>> {
        self.target.clone()
    }

    pub fn GetCurrentTarget(&self) -> Option<JS<EventTarget>> {
        self.current_target.clone()
    }

    pub fn DefaultPrevented(&self) -> bool {
        self.canceled
    }

    pub fn PreventDefault(&mut self) {
        if self.cancelable {
            self.canceled = true
        }
    }

    pub fn StopPropagation(&mut self) {
        self.stop_propagation = true;
    }

    pub fn StopImmediatePropagation(&mut self) {
        self.stop_immediate = true;
        self.stop_propagation = true;
    }

    pub fn Bubbles(&self) -> bool {
        self.bubbles
    }

    pub fn Cancelable(&self) -> bool {
        self.cancelable
    }

    pub fn TimeStamp(&self) -> u64 {
        0
    }

    pub fn InitEvent(&mut self,
                     type_: DOMString,
                     bubbles: bool,
                     cancelable: bool) {
        self.type_ = type_;
        self.cancelable = cancelable;
        self.bubbles = bubbles;
        self.initialized = true;
        self.canceled = false;
    }

    pub fn IsTrusted(&self) -> bool {
        self.trusted
    }

    pub fn Constructor(global: &JS<Window>,
                       type_: DOMString,
                       init: &EventBinding::EventInit) -> Fallible<JS<Event>> {
        let mut ev = Event::new(global);
        ev.get_mut().InitEvent(type_, init.bubbles, init.cancelable);
        Ok(ev)
    }
}

impl Reflectable for Event {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        &mut self.reflector_
    }
}
<commit_msg>set the right flags and attrs for InitEvent<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::EventBinding;
use dom::bindings::codegen::EventBinding::EventConstants;
use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::error::Fallible;
use dom::eventtarget::EventTarget;
use dom::window::Window;
use servo_util::str::DOMString;

use geom::point::Point2D;

pub enum Event_ {
    ResizeEvent(uint, uint),
    ReflowEvent,
    ClickEvent(uint, Point2D<f32>),
    MouseDownEvent(uint, Point2D<f32>),
    MouseUpEvent(uint, Point2D<f32>),
    MouseMoveEvent(Point2D<f32>)
}

#[deriving(Encodable)]
pub enum EventPhase {
    PhaseNone      = EventConstants::NONE,
    PhaseCapturing = EventConstants::CAPTURING_PHASE,
    PhaseAtTarget  = EventConstants::AT_TARGET,
    PhaseBubbling  = EventConstants::BUBBLING_PHASE,
}

#[deriving(Eq, Encodable)]
pub enum EventTypeId {
    HTMLEventTypeId,
    UIEventTypeId,
    MouseEventTypeId,
    KeyEventTypeId
}

#[deriving(Encodable)]
pub struct Event {
    type_id: EventTypeId,
    reflector_: Reflector,
    current_target: Option<JS<EventTarget>>,
    target: Option<JS<EventTarget>>,
    type_: DOMString,
    phase: EventPhase,
    canceled: bool,
    stop_propagation: bool,
    stop_immediate: bool,
    cancelable: bool,
    bubbles: bool,
    trusted: bool,
    dispatching: bool,
    initialized: bool,
}

impl Event {
    pub fn new_inherited(type_id: EventTypeId) -> Event {
        Event {
            type_id: type_id,
            reflector_: Reflector::new(),
            current_target: None,
            target: None,
            phase: PhaseNone,
            type_: ~"",
            canceled: false,
            cancelable: true,
            bubbles: true,
            trusted: false,
            dispatching: false,
            stop_propagation: false,
            stop_immediate: false,
            initialized: false,
        }
    }

    pub fn new(window: &JS<Window>) -> JS<Event> {
        reflect_dom_object(~Event::new_inherited(HTMLEventTypeId),
                           window,
                           EventBinding::Wrap)
    }

    pub fn EventPhase(&self) -> u16 {
        self.phase as u16
    }

    pub fn Type(&self) -> DOMString {
        self.type_.clone()
    }

    pub fn GetTarget(&self) -> Option<JS<EventTarget>> {
        self.target.clone()
    }

    pub fn GetCurrentTarget(&self) -> Option<JS<EventTarget>> {
        self.current_target.clone()
    }

    pub fn DefaultPrevented(&self) -> bool {
        self.canceled
    }

    pub fn PreventDefault(&mut self) {
        if self.cancelable {
            self.canceled = true
        }
    }

    pub fn StopPropagation(&mut self) {
        self.stop_propagation = true;
    }

    pub fn StopImmediatePropagation(&mut self) {
        self.stop_immediate = true;
        self.stop_propagation = true;
    }

    pub fn Bubbles(&self) -> bool {
        self.bubbles
    }

    pub fn Cancelable(&self) -> bool {
        self.cancelable
    }

    pub fn TimeStamp(&self) -> u64 {
        0
    }

    pub fn InitEvent(&mut self,
                     type_: DOMString,
                     bubbles: bool,
                     cancelable: bool) {
        self.initialized = true;
        if self.dispatching {
            return;
        }
        self.stop_propagation = false;
        self.stop_immediate = false;
        self.canceled = false;
        self.trusted = false;
        self.target = None;
        self.type_ = type_;
        self.bubbles = bubbles;
        self.cancelable = cancelable;
    }

    pub fn IsTrusted(&self) -> bool {
        self.trusted
    }

    pub fn Constructor(global: &JS<Window>,
                       type_: DOMString,
                       init: &EventBinding::EventInit) -> Fallible<JS<Event>> {
        let mut ev = Event::new(global);
        ev.get_mut().InitEvent(type_, init.bubbles, init.cancelable);
        Ok(ev)
    }
}

impl Reflectable for Event {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        &mut self.reflector_
    }
}
<|endoftext|>