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

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value. This can happen when
trying to import a method from a trait. An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn do_something();
    }
}
use foo::MyTrait::do_something;
```

In general, it's not legal to directly import methods belonging to a
trait or concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##

E0403: r##"
Some type parameters have the same name. Example of erroneous code:

```
fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
                            //        parameter in this type parameter list
```

Please verify that none of the type params are misspelled, and rename any
clashing parameters. Example:

```
fn foo<T, Y>(s: T, u: Y) {} // ok!
```
"##,

E0404: r##"
You tried to implement a non-trait object on an object. Example of erroneous
code:

```
struct Foo;
struct Bar;

impl Foo for Bar {} // error: `Foo` is not a trait
```

Please verify you didn't mispelled the trait's name or used the wrong object.
Example:

```
trait Foo {
    // some functions
}
struct Bar;

impl Foo for Bar { // ok!
    // functions implementation
}
```
"##,

E0405: r##"
A non-trait was implemented. Example of erroneous code:

```
struct Foo;

impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
```

Please verify that the name of the trait wasn't misspelled and ensure that it
was imported. Example:

```
// solution 1:
use some_file::SomeTrait;

// solution 2:
trait SomeTrait {
    // some functions
}

struct Foo;

impl SomeTrait for Foo { // ok!
    // implements functions
}
```
"##,

E0407: r##"
A definition of a method not in the implemented trait was given. Example of
erroneous code:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // error: method `b` is not a member of trait `Foo`
}
```

Please verify you didn't mispelled the method name and you used the good
trait. Example:

```
trait Foo {
    fn a();
    fn b();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // ok!
}
```
"##,

E0428: r##"
A type or module has been defined more than once. Example of erroneous
code:

```
struct Bar;
struct Bar; // error: duplicate definition of value `Bar`
```

Please verify you didn't mispelled the type/module's name or remove the
duplicated one. Example:

```
struct Bar;
struct Bar2; // ok!
```
"##,

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0406, // undeclared associated type
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0417, // static variables cannot be referenced in a pattern, use a
           // `const` instead
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0424, // `self` is not available in a static method.
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0429, // `self` imports are only allowed within a { } list
    E0430, // `self` import can only appear once in the list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0433, // failed to resolve
    E0434, // can't capture dynamic environment in a fn item
    E0435, // attempt to use a non-constant value in a constant
    E0437, // type is not a member of trait
    E0438, // const is not a member of trait
}
<commit_msg>Add E0433 error explanation<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value. This can happen when
trying to import a method from a trait. An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn do_something();
    }
}
use foo::MyTrait::do_something;
```

In general, it's not legal to directly import methods belonging to a
trait or concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0403: r##"
Some type parameters have the same name. Example of erroneous code:

```
fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
                            //        parameter in this type parameter list
```

Please verify that none of the type parameterss are misspelled, and rename any
clashing parameters. Example:

```
fn foo<T, Y>(s: T, u: Y) {} // ok!
```
"##,

E0404: r##"
You tried to implement something which was not a trait on an object. Example of
erroneous code:

```
struct Foo;
struct Bar;

impl Foo for Bar {} // error: `Foo` is not a trait
```

Please verify that you didn't misspell the trait's name or otherwise use the
wrong identifier. Example:

```
trait Foo {
    // some functions
}
struct Bar;

impl Foo for Bar { // ok!
    // functions implementation
}
```
"##,

E0405: r##"
An unknown trait was implemented. Example of erroneous code:

```
struct Foo;

impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
```

Please verify that the name of the trait wasn't misspelled and ensure that it
was imported. Example:

```
// solution 1:
use some_file::SomeTrait;

// solution 2:
trait SomeTrait {
    // some functions
}

struct Foo;

impl SomeTrait for Foo { // ok!
    // implements functions
}
```
"##,

E0407: r##"
A definition of a method not in the implemented trait was given in a trait
implementation. Example of erroneous code:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // error: method `b` is not a member of trait `Foo`
}
```

Please verify you didn't misspell the method name and you used the correct
trait. First example:

```
trait Foo {
    fn a();
    fn b();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // ok!
}
```

Second example:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
}

impl Bar {
    fn b() {}
}
```
"##,

E0428: r##"
A type or module has been defined more than once. Example of erroneous
code:

```
struct Bar;
struct Bar; // error: duplicate definition of value `Bar`
```

Please verify you didn't misspell the type/module's name or remove/rename the
duplicated one. Example:

```
struct Bar;
struct Bar2; // ok!
```
"##,

E0433: r##"
Invalid import. Example of erroneous code:

```
use something_which_doesnt_exist;
// error: unresolved import `something_which_doesnt_exist`
```

Please verify you didn't misspell the import's name.
"##,

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0406, // undeclared associated type
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0417, // static variables cannot be referenced in a pattern, use a
           // `const` instead
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0424, // `self` is not available in a static method.
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0429, // `self` imports are only allowed within a { } list
    E0430, // `self` import can only appear once in the list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0434, // can't capture dynamic environment in a fn item
    E0435, // attempt to use a non-constant value in a constant
    E0437, // type is not a member of trait
    E0438, // const is not a member of trait
}
<|endoftext|>


<commit_before>use super::super::chunk::{Chunk, Chunks};
use super::super::segs::{Segment, EntryMeta};
use ram::repr::EntryType;
use ram::cell::{Cell, CellHeader};
use ram::tombstone::Tombstone;
use dovahkiin::types::Id;

use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use std::collections::BTreeSet;
use std::collections::Bound::{Included, Unbounded};

use libc;
use parking_lot::MutexGuard;

static MAX_CLEAN_RETRY: u16 = 100;

pub fn ceiling_frag(frags: &MutexGuard<BTreeSet<usize>>, location: usize) -> Option<usize> {
    match frags.range((Included(&location), Unbounded)).next() {
        Some(l) => Some(*l),
        None => None
    }
}

pub struct CompactCleaner {
    chunks: Arc<Chunks>,
    closed: AtomicBool
}

enum EntryContent {
    Cell(CellHeader),
    Tombstone(Tombstone),
    Undecided
}

struct Entry {
    meta: EntryMeta,
    content: EntryContent
}

impl CompactCleaner {
    pub fn clean_segment(chunk: &Chunk, seg: &Segment) {
        // Clean only if segment have fragments
        if seg.total_dead_space() == 0 {return;}
        // Retry cleaning the segment if unexpected state discovered
        let mut retried = 0;
        // Previous implementation is inplace compaction. Segments are mutable and subject to changes.
        // Log-structured cleaner suggests new segment allocation and copy living entries from the
        // old segment to new segment. The new segment should have smaller sizes than the old one.
        // In this way locks can be straight forward, copy those entries to the new segment, change
        // cell indices by lock cells first, remove the old segment.
        // Segment locks will no long be required for transfer process will ensure there will be no
        // on going read operations to the old segment when the segment to be deleted.

        // Some comments regards to RAMCloud seglets. To compress the actual memory spaces consumed by
        // segments, RAMCloud introduces seglets as the minimal unit of the memory. It records a mapping
        // from segment to seglets it consumed. In this case, compacted segments will take less seglets.
        // Freed seglets will be used by other new allocated segments, which can leads to incontinently.
        // Actually, malloc already handled this situation to overcome fragmentation, we can simply use
        // malloc to allocate new memory spaces for segments than maintaining seglets mappings in userspace.
        debug!("Cleaning segment {} from chunk {}", seg.id, chunk.id);

        // scan and mark live entries
        let live = seg.entry_iter()
            .filter_map(|entry_meta| {
                let entry_size = entry_meta.entry_size;
                let entry_header = entry_meta.entry_header;
                match entry_header.entry_type {
                    EntryType::Cell => {
                        let cell_header =
                            Cell::cell_header_from_entry_content_addr(
                                entry_meta.body_pos, &entry_header);
                        if chunk.index
                            .get(&cell_header.hash)
                            .map(|g| *g) == Some(entry_meta.entry_pos) {
                            return Some((Entry {
                                meta: entry_meta,
                                content: EntryContent::Cell(cell_header)
                            }, entry_size));
                        }
                    },
                    EntryType::Tombstone => {
                        let tombstone =
                            Tombstone::read_from_entry_content_addr(entry_meta.body_pos);
                        if chunk.segs.contains_key(&tombstone.segment_id) {
                            return Some((Entry {
                                meta: entry_meta,
                                content: EntryContent::Tombstone(tombstone)
                            }, entry_size));
                        }
                    },
                    _ => panic!("Unexpected cell type on compaction: {:?}, size {}",
                                entry_header, entry_size)
                }
                return None
            });
        let (entries, sizes) : (Vec<_>, Vec<_>) = live.unzip();
        let live_size: usize = sizes.into_iter().sum();
        debug!("Segment {} from chunk {} have {} live objects. Total size {} bytes for new segment.",
               seg.id, chunk.id, entries.len(), live_size);
        let new_seg_id = chunk.seg_counter.fetch_add(1, Ordering::Relaxed);
        let new_seg = Segment::new(new_seg_id, live_size);
        let mut cursor = new_seg.addr;
        let copied_entries = entries.iter().map(|e: &Entry| {
            let entry_size = e.meta.entry_size;
            let result= (e, cursor);
            unsafe {
                libc::memcpy(
                    cursor as *mut libc::c_void,
                    e.meta.entry_pos as *mut libc::c_void,
                    entry_size);
            }
            cursor += entry_size;
            return result;
        });
    }
}<commit_msg>update cell address chunk index<commit_after>use super::super::chunk::{Chunk, Chunks};
use super::super::segs::{Segment, EntryMeta};
use ram::repr::EntryType;
use ram::cell::{Cell, CellHeader};
use ram::tombstone::Tombstone;
use dovahkiin::types::Id;

use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::sync::Arc;
use std::time::Duration;
use std::collections::BTreeSet;
use std::collections::Bound::{Included, Unbounded};

use libc;
use parking_lot::MutexGuard;

static MAX_CLEAN_RETRY: u16 = 100;

pub fn ceiling_frag(frags: &MutexGuard<BTreeSet<usize>>, location: usize) -> Option<usize> {
    match frags.range((Included(&location), Unbounded)).next() {
        Some(l) => Some(*l),
        None => None
    }
}

pub struct CompactCleaner {
    chunks: Arc<Chunks>,
    closed: AtomicBool
}

enum EntryContent {
    Cell(CellHeader),
    Tombstone(Tombstone),
    Undecided
}

struct Entry {
    meta: EntryMeta,
    content: EntryContent
}

impl CompactCleaner {
    pub fn clean_segment(chunk: &Chunk, seg: &Segment) {
        // Clean only if segment have fragments
        if seg.total_dead_space() == 0 {return;}
        // Retry cleaning the segment if unexpected state discovered
        let mut retried = 0;
        // Previous implementation is inplace compaction. Segments are mutable and subject to changes.
        // Log-structured cleaner suggests new segment allocation and copy living entries from the
        // old segment to new segment. The new segment should have smaller sizes than the old one.
        // In this way locks can be straight forward, copy those entries to the new segment, change
        // cell indices by lock cells first, remove the old segment.
        // Segment locks will no long be required for transfer process will ensure there will be no
        // on going read operations to the old segment when the segment to be deleted.

        // Some comments regards to RAMCloud seglets. To compress the actual memory spaces consumed by
        // segments, RAMCloud introduces seglets as the minimal unit of the memory. It records a mapping
        // from segment to seglets it consumed. In this case, compacted segments will take less seglets.
        // Freed seglets will be used by other new allocated segments, which can leads to incontinently.
        // Actually, malloc already handled this situation to overcome fragmentation, we can simply use
        // malloc to allocate new memory spaces for segments than maintaining seglets mappings in userspace.
        debug!("Cleaning segment {} from chunk {}", seg.id, chunk.id);

        // scan and mark live entries
        let live = seg.entry_iter()
            .filter_map(|entry_meta| {
                let entry_size = entry_meta.entry_size;
                let entry_header = entry_meta.entry_header;
                match entry_header.entry_type {
                    EntryType::Cell => {
                        let cell_header =
                            Cell::cell_header_from_entry_content_addr(
                                entry_meta.body_pos, &entry_header);
                        if chunk.index
                            .get(&cell_header.hash)
                            .map(|g| *g) == Some(entry_meta.entry_pos) {
                            return Some((Entry {
                                meta: entry_meta,
                                content: EntryContent::Cell(cell_header)
                            }, entry_size));
                        }
                    },
                    EntryType::Tombstone => {
                        let tombstone =
                            Tombstone::read_from_entry_content_addr(entry_meta.body_pos);
                        if chunk.segs.contains_key(&tombstone.segment_id) {
                            return Some((Entry {
                                meta: entry_meta,
                                content: EntryContent::Tombstone(tombstone)
                            }, entry_size));
                        }
                    },
                    _ => panic!("Unexpected cell type on compaction: {:?}, size {}",
                                entry_header, entry_size)
                }
                return None
            });
        let (entries, sizes) : (Vec<_>, Vec<_>) = live.unzip();
        let live_size: usize = sizes.into_iter().sum();
        debug!("Segment {} from chunk {} have {} live objects. Total size {} bytes for new segment.",
               seg.id, chunk.id, entries.len(), live_size);
        let new_seg_id = chunk.seg_counter.fetch_add(1, Ordering::Relaxed);
        let new_seg = Segment::new(new_seg_id, live_size);
        let mut cursor = new_seg.addr;
        let copied_entries = entries.iter().map(|e: &Entry| {
            let entry_size = e.meta.entry_size;
            let result= (e, cursor);
            unsafe {
                libc::memcpy(
                    cursor as *mut libc::c_void,
                    e.meta.entry_pos as *mut libc::c_void,
                    entry_size);
            }
            cursor += entry_size;
            return result;
        });

        // update cell address chunk index
        copied_entries
            .filter(|pair|
                pair.0.meta.entry_header.entry_type == EntryType::Cell)
            .for_each(|(entry, new_addr)| {
                if let EntryContent::Cell(header) = entry.content {
                    if let Some(mut cell_guard) = chunk.index.get_mut(&header.hash) {
                        let old_addr = entry.meta.entry_pos;
                        if *cell_guard == old_addr {
                            *cell_guard = new_addr;
                        } else {
                            warn!("cell address {} have been changed to {} on relocating on cleaning",
                                  old_addr, *cell_guard);
                        }
                    }
                } else {
                    panic!("not cell after filter")
                }
            });
    }
}<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Roots_of_a_function

fn find_roots<T: Copy + PartialOrd + Signed>(f: |T| -> T, start: T, stop: T,
                                             step: T, epsilon: T) -> Vec<T> {
    let mut ret = vec![];
    let mut current = start;
    while current < stop {
        if f(current).abs() < epsilon {
            ret.push(current);
        }
        current = current + step;
    }
    ret
}

#[test]
fn test_find_roots() {
    let roots = find_roots(|x: f64| x*x*x - 3.0*x*x + 2.0*x,
                           -1.0, 3.0, 0.0001, 0.00000001);
    let expected = [0.0f64, 1.0, 2.0];

    for (&a, &b) in roots.iter().zip(expected.iter()) {
        assert!((a - b).abs() < 0.0001);
    }
}

#[cfg(not(test))]
fn main() {
    let roots = find_roots(|x: f64| x*x*x - 3.0*x*x + 2.0*x,
                           -1.0, 3.0, 0.0001, 0.00000001);

    println!("roots of f(x) = x^3 - 3x^2 + 2x are: {}", roots);
}
<commit_msg>Add a note on why we cannot use `range_step` here.<commit_after>// http://rosettacode.org/wiki/Roots_of_a_function

// Note: We cannot use `range_step` here because Floats don't implement
// the `CheckedAdd` trait.
fn find_roots<T: Copy + PartialOrd + Signed>(f: |T| -> T, start: T, stop: T,
                                             step: T, epsilon: T) -> Vec<T> {
    let mut ret = vec![];
    let mut current = start;
    while current < stop {
        if f(current).abs() < epsilon {
            ret.push(current);
        }
        current = current + step;
    }
    ret
}

#[test]
fn test_find_roots() {
    let roots = find_roots(|x: f64| x*x*x - 3.0*x*x + 2.0*x,
                           -1.0, 3.0, 0.0001, 0.00000001);
    let expected = [0.0f64, 1.0, 2.0];

    for (&a, &b) in roots.iter().zip(expected.iter()) {
        assert!((a - b).abs() < 0.0001);
    }
}

#[cfg(not(test))]
fn main() {
    let roots = find_roots(|x: f64| x*x*x - 3.0*x*x + 2.0*x,
                           -1.0, 3.0, 0.0001, 0.00000001);

    println!("roots of f(x) = x^3 - 3x^2 + 2x are: {}", roots);
}
<|endoftext|>


<commit_before>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::{InstBuilder, InstructionData, Opcode};
use ir::immediates::Imm64;
use stack_layout::layout_stack;
use cursor::{Cursor, EncCursor};

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        let word_size = if self.flags().is_64bit() { 8 } else { 4 };
        let csr_type = if self.flags().is_64bit() {
            ir::types::I64
        } else {
            ir::types::I32
        };
        let csrs = abi::callee_saved_registers(&self.shared_flags);

        let mut csr_stack_size = word_size; // Size of RBP to start with
        for _reg in &csrs {
            csr_stack_size += word_size;
        }

        let stack_offset = -(csr_stack_size as i32);
        let slot = ir::StackSlotData {
            kind: ir::StackSlotKind::IncomingArg,
            size: csr_stack_size,
            offset: stack_offset,
        };
        func.create_stack_slot(slot);

        let total_stack_size = layout_stack(&mut func.stack_slots, word_size)?;
        let local_stack_size = (total_stack_size - csr_stack_size) as i64;

        // Build up list of args, which we'll append forwards to the params and
        // backwards to the returns.
        let mut csr_args = Vec::new();
        csr_args.push(ir::AbiParam::special_reg(
            csr_type,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        ));
        for reg in &csrs {
            csr_args.push(ir::AbiParam::special_reg(
                csr_type,
                ir::ArgumentPurpose::CalleeSaved,
                *reg as RegUnit,
            ));
        }

        for csr_arg in &csr_args {
            func.signature.params.push(*csr_arg);
        }
        for csr_arg in csr_args.iter().rev() {
            func.signature.returns.push(*csr_arg);
        }

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        let fp = func.dfg.append_ebb_param(entry_ebb, csr_type);

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        let mut csr_vals = Vec::new();
        for reg in &csrs {
            // Append param to entry EBB
            let csr_arg = func.dfg.append_ebb_param(entry_ebb, csr_type);

            // Assign it a location
            func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);

            // Remember it so we can push it momentarily
            csr_vals.push(csr_arg);
        }

        // Insert prologue
        {
            let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
            pos.ins().x86_push(fp);
            pos.ins().copy_special(
                RU::rsp as RegUnit,
                RU::rbp as RegUnit,
            );
            if local_stack_size > 0 {
                pos.ins().adjust_sp_imm(Imm64::new(-local_stack_size));
            }

            for csr_arg in csr_vals {
                pos.ins().x86_push(csr_arg);
            }
        }

        // Find all 'return' instructions
        let mut return_insts = Vec::new();
        for ebb in func.layout.ebbs() {
            for inst in func.layout.ebb_insts(ebb) {
                if let InstructionData::MultiAry { opcode, .. } = func.dfg[inst] {
                    if opcode == Opcode::Return {
                        return_insts.push(inst);
                    }
                }

            }
        }

        // Insert an epilogue directly before every 'return'
        for inst in return_insts {
            self.insert_epilogue(inst, local_stack_size, func, &csrs, csr_type);
        }

        Ok(())
    }
}

impl Isa {
    fn insert_epilogue(
        &self,
        inst: ir::Inst,
        stack_size: i64,
        func: &mut ir::Function,
        csrs: &Vec<RU>,
        csr_type: ir::types::Type,
    ) {
        let mut return_values = Vec::new();

        let mut pos = EncCursor::new(func, self).at_inst(inst);
        if stack_size > 0 {
            pos.ins().adjust_sp_imm(Imm64::new(stack_size));
        }
        for reg in csrs.iter().rev() {
            let csr_ret = pos.ins().x86_pop(csr_type);
            return_values.push((csr_ret, *reg));
        }
        let fp_ret = pos.ins().x86_pop(csr_type);
        return_values.push((fp_ret, RU::rbp));

        let func = pos.func;
        for (val, reg) in return_values {
            func.locations[val] = ir::ValueLoc::Reg(reg as RegUnit);
            func.dfg.append_inst_arg(inst, val);
        }
    }
}
<commit_msg>Use opcode's is_return() rather than pattern-matching.<commit_after>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::{InstBuilder, InstructionData, Opcode};
use ir::immediates::Imm64;
use stack_layout::layout_stack;
use cursor::{Cursor, EncCursor};

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        let word_size = if self.flags().is_64bit() { 8 } else { 4 };
        let csr_type = if self.flags().is_64bit() {
            ir::types::I64
        } else {
            ir::types::I32
        };
        let csrs = abi::callee_saved_registers(&self.shared_flags);

        let mut csr_stack_size = word_size; // Size of RBP to start with
        for _reg in &csrs {
            csr_stack_size += word_size;
        }

        let stack_offset = -(csr_stack_size as i32);
        let slot = ir::StackSlotData {
            kind: ir::StackSlotKind::IncomingArg,
            size: csr_stack_size,
            offset: stack_offset,
        };
        func.create_stack_slot(slot);

        let total_stack_size = layout_stack(&mut func.stack_slots, word_size)?;
        let local_stack_size = (total_stack_size - csr_stack_size) as i64;

        // Build up list of args, which we'll append forwards to the params and
        // backwards to the returns.
        let mut csr_args = Vec::new();
        csr_args.push(ir::AbiParam::special_reg(
            csr_type,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        ));
        for reg in &csrs {
            csr_args.push(ir::AbiParam::special_reg(
                csr_type,
                ir::ArgumentPurpose::CalleeSaved,
                *reg as RegUnit,
            ));
        }

        for csr_arg in &csr_args {
            func.signature.params.push(*csr_arg);
        }
        for csr_arg in csr_args.iter().rev() {
            func.signature.returns.push(*csr_arg);
        }

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        let fp = func.dfg.append_ebb_param(entry_ebb, csr_type);

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        let mut csr_vals = Vec::new();
        for reg in &csrs {
            // Append param to entry EBB
            let csr_arg = func.dfg.append_ebb_param(entry_ebb, csr_type);

            // Assign it a location
            func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);

            // Remember it so we can push it momentarily
            csr_vals.push(csr_arg);
        }

        // Insert prologue
        {
            let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
            pos.ins().x86_push(fp);
            pos.ins().copy_special(
                RU::rsp as RegUnit,
                RU::rbp as RegUnit,
            );
            if local_stack_size > 0 {
                pos.ins().adjust_sp_imm(Imm64::new(-local_stack_size));
            }

            for csr_arg in csr_vals {
                pos.ins().x86_push(csr_arg);
            }
        }

        // Find all 'return' instructions
        let mut return_insts = Vec::new();
        for ebb in func.layout.ebbs() {
            for inst in func.layout.ebb_insts(ebb) {
                if func.dfg[inst].opcode().is_return() {
                    return_insts.push(inst);
                }
            }
        }

        // Insert an epilogue directly before every 'return'
        for inst in return_insts {
            self.insert_epilogue(inst, local_stack_size, func, &csrs, csr_type);
        }

        Ok(())
    }
}

impl Isa {
    fn insert_epilogue(
        &self,
        inst: ir::Inst,
        stack_size: i64,
        func: &mut ir::Function,
        csrs: &Vec<RU>,
        csr_type: ir::types::Type,
    ) {
        let mut return_values = Vec::new();

        let mut pos = EncCursor::new(func, self).at_inst(inst);
        if stack_size > 0 {
            pos.ins().adjust_sp_imm(Imm64::new(stack_size));
        }
        for reg in csrs.iter().rev() {
            let csr_ret = pos.ins().x86_pop(csr_type);
            return_values.push((csr_ret, *reg));
        }
        let fp_ret = pos.ins().x86_pop(csr_type);
        return_values.push((fp_ret, RU::rbp));

        let func = pos.func;
        for (val, reg) in return_values {
            func.locations[val] = ir::ValueLoc::Reg(reg as RegUnit);
            func.dfg.append_inst_arg(inst, val);
        }
    }
}
<|endoftext|>


<commit_before>export build_display_list;

use css::values::{BgColor, BgTransparent, Specified};
use base::{Box, BTree, ImageHolder, TextBoxKind};
use dl = layout::display_list;
use dom::base::{Text, NodeScope};
use dom::rcu::Scope;
use either::{Left, Right};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::geometry::{au, au_to_px, box, px_to_au};
use util::tree;

use dvec::DVec;
use vec::push;

#[doc = "

Builds a display list for a box and all its children

"]
fn build_display_list(box : @Box) -> dl::DisplayList {
    let list = DVec();
    build_display_list_from_origin(list, box, Point2D(au(0), au(0)));
    return list;
}

#[doc="

Builds a display list for a box and all its children.

# Arguments

* `box` - The box to build the display list for.
* `origin` - The coordinates of upper-left corner of the box containing the
             passed-in box.

"]
fn build_display_list_from_origin(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {
    let box_origin = Point2D(
        px_to_au(au_to_px(origin.x) + au_to_px(box.bounds.origin.x)),
        px_to_au(au_to_px(origin.y) + au_to_px(box.bounds.origin.y)));
    #debug("Handed origin %?, box has bounds %?, starting with origin %?", origin, copy box.bounds, box_origin);

    box_to_display_items(list, box, box_origin);

    for BTree.each_child(box) |c| {
        #debug("Recursively building display list with origin %?", box_origin);
        build_display_list_from_origin(list, c, box_origin);
    }
}

#[doc="

Creates a display list item for a single block.

# Arguments

* `box` - The box to build the display list for
* `origin` - The coordinates of upper-left corner of the passed in box.

"]
#[allow(non_implicitly_copyable_typarams)]
fn box_to_display_items(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {

    // TODO: each box should know how to make its own display items.
    // The display list builder should mainly hold information about
    // the initial request and desired result---for example, is the
    // DisplayList to be used for painting or hit testing. This can
    // influence which boxes are created.

    // TODO: to implement stacking contexts correctly, we need to
    // create a set of display lists, one per each layer of a stacking
    // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
    // set representing the box's stacking context. When asked to
    // construct its constituent display items, each box puts its
    // DisplayItems into the correct stack layer (according to CSS 2.1
    // Appendix E).  and then builder flattens the list at the end.

    #debug("request to display a box from origin %?", origin);

    let bounds : Rect<au> = Rect(origin, copy box.bounds.size);

    match box.kind {
      TextBoxKind(subbox) => {
        let run = copy subbox.run;
        assert run.is_some();
        list.push(~dl::SolidColor(bounds, 255u8, 255u8, 255u8));
        list.push(~dl::Text(bounds, run.get()));
        return;
      }
      _ => {
        // Fall through
      }
    };

    // Check if there is a background image, if not set the background color.
    let image = box.appearance.get_image();

    if image.is_some() {
        list.push(~dl::Image(bounds, option::unwrap(image)))
    } else {
        // DAC
        // TODO: shouldn't need to unbox CSSValue by now
        let boxed_color = box.node.get_specified_style().background_color;
        let color = match boxed_color {
            Specified(BgColor(c)) => c,
            Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0)
        };
        #debug("Assigning color %? to box with bounds %?", color, bounds);
        list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
    }
}

fn should_convert_text_boxes_to_solid_color_background_items() {
    #[test];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => subbox,
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    do list.borrow |l| {
        match l[0].item {
            dl::SolidColor(*) => { }
            _ => { fail }
        }
    }
}

fn should_convert_text_boxes_to_text_items() {
    #[test];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => { subbox },
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    do list.borrow |l| {
        match l[1].item {
            dl::Text(_) => { }
            _ => { fail }
        }
    }
}

fn should_calculate_the_bounds_of_the_text_box_background_color() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => { subbox },
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    let expected = Rect(
        Point2D(px_to_au(0), px_to_au(0)),
        Size2D(px_to_au(84), px_to_au(20))
    );

    do list.borrow |l| { assert l[0].bounds == expected }
}

fn should_calculate_the_bounds_of_the_text_items() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => { subbox },
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    let expected = Rect(
        Point2D(px_to_au(0), px_to_au(0)),
        Size2D(px_to_au(84), px_to_au(20))
    );

    do list.borrow |l| { assert l[1].bounds == expected; }
}
<commit_msg>Fix breakage in display_list_builder tests<commit_after>export build_display_list;

use css::values::{BgColor, BgTransparent, Specified};
use base::{Box, BTree, ImageHolder, TextBoxKind};
use dl = layout::display_list;
use dom::base::{Text, NodeScope};
use dom::rcu::Scope;
use either::{Left, Right};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::geometry::{au, au_to_px, box, px_to_au};
use util::tree;

use dvec::DVec;
use vec::push;

#[doc = "

Builds a display list for a box and all its children

"]
fn build_display_list(box : @Box) -> dl::DisplayList {
    let list = DVec();
    build_display_list_from_origin(list, box, Point2D(au(0), au(0)));
    return list;
}

#[doc="

Builds a display list for a box and all its children.

# Arguments

* `box` - The box to build the display list for.
* `origin` - The coordinates of upper-left corner of the box containing the
             passed-in box.

"]
fn build_display_list_from_origin(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {
    let box_origin = Point2D(
        px_to_au(au_to_px(origin.x) + au_to_px(box.bounds.origin.x)),
        px_to_au(au_to_px(origin.y) + au_to_px(box.bounds.origin.y)));
    #debug("Handed origin %?, box has bounds %?, starting with origin %?", origin, copy box.bounds, box_origin);

    box_to_display_items(list, box, box_origin);

    for BTree.each_child(box) |c| {
        #debug("Recursively building display list with origin %?", box_origin);
        build_display_list_from_origin(list, c, box_origin);
    }
}

#[doc="

Creates a display list item for a single block.

# Arguments

* `box` - The box to build the display list for
* `origin` - The coordinates of upper-left corner of the passed in box.

"]
#[allow(non_implicitly_copyable_typarams)]
fn box_to_display_items(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {

    // TODO: each box should know how to make its own display items.
    // The display list builder should mainly hold information about
    // the initial request and desired result---for example, is the
    // DisplayList to be used for painting or hit testing. This can
    // influence which boxes are created.

    // TODO: to implement stacking contexts correctly, we need to
    // create a set of display lists, one per each layer of a stacking
    // context. (CSS 2.1, Section 9.9.1). Each box is passed the list
    // set representing the box's stacking context. When asked to
    // construct its constituent display items, each box puts its
    // DisplayItems into the correct stack layer (according to CSS 2.1
    // Appendix E).  and then builder flattens the list at the end.

    #debug("request to display a box from origin %?", origin);

    let bounds : Rect<au> = Rect(origin, copy box.bounds.size);

    match box.kind {
      TextBoxKind(subbox) => {
        let run = copy subbox.run;
        assert run.is_some();
        list.push(~dl::SolidColor(bounds, 255u8, 255u8, 255u8));
        list.push(~dl::Text(bounds, run.get()));
        return;
      }
      _ => {
        // Fall through
      }
    };

    // Check if there is a background image, if not set the background color.
    let image = box.appearance.get_image();

    if image.is_some() {
        list.push(~dl::Image(bounds, option::unwrap(image)))
    } else {
        // DAC
        // TODO: shouldn't need to unbox CSSValue by now
        let boxed_color = box.node.get_specified_style().background_color;
        let color = match boxed_color {
            Specified(BgColor(c)) => c,
            Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0)
        };
        #debug("Assigning color %? to box with bounds %?", color, bounds);
        list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
    }
}

fn should_convert_text_boxes_to_solid_color_background_items() {
    #[test];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => subbox,
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    do list.borrow |l| {
        match l[0].data {
            dl::SolidColorData(*) => { }
            _ => { fail }
        }
    }
}

fn should_convert_text_boxes_to_text_items() {
    #[test];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => { subbox },
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    do list.borrow |l| {
        match l[1].data {
            dl::TextData(_) => { }
            _ => { fail }
        }
    }
}

fn should_calculate_the_bounds_of_the_text_box_background_color() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => { subbox },
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    let expected = Rect(
        Point2D(px_to_au(0), px_to_au(0)),
        Size2D(px_to_au(84), px_to_au(20))
    );

    do list.borrow |l| { assert l[0].bounds == expected }
}

fn should_calculate_the_bounds_of_the_text_items() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let s = Scope();
    let n = s.new_node(Text(~"firecracker"));
    let b = n.construct_boxes().get();

    let subbox = match b.kind {
      TextBoxKind(subbox) => { subbox },
      _ => fail
    };

    b.reflow_text(subbox);
    let list = DVec();
    box_to_display_items(list, b, Point2D(px_to_au(0), px_to_au(0)));

    let expected = Rect(
        Point2D(px_to_au(0), px_to_au(0)),
        Size2D(px_to_au(84), px_to_au(20))
    );

    do list.borrow |l| { assert l[1].bounds == expected; }
}
<|endoftext|>


<commit_before>//! Abstractions for reading and modifying the mapping of pages.

pub use self::mapped_page_table::{MappedPageTable, PhysToVirt};
#[cfg(target_arch = "x86_64")]
pub use self::{offset_page_table::OffsetPageTable, recursive_page_table::RecursivePageTable};

use crate::structures::paging::{
    frame_alloc::FrameAllocator, page_table::PageTableFlags, Page, PageSize, PhysFrame, Size1GiB,
    Size2MiB, Size4KiB,
};
use crate::{PhysAddr, VirtAddr};

mod mapped_page_table;
mod offset_page_table;
mod recursive_page_table;

/// This trait defines page table operations that work for all page sizes of the x86_64
/// architecture.
pub trait MapperAllSizes: Mapper<Size4KiB> + Mapper<Size2MiB> + Mapper<Size1GiB> {
    /// Return the frame that the given virtual address is mapped to and the offset within that
    /// frame.
    ///
    /// If the given address has a valid mapping, the mapped frame and the offset within that
    /// frame is returned. Otherwise an error value is returned.
    ///
    /// This function works with huge pages of all sizes.
    fn translate(&self, addr: VirtAddr) -> TranslateResult;

    /// Translates the given virtual address to the physical address that it maps to.
    ///
    /// Returns `None` if there is no valid mapping for the given address.
    ///
    /// This is a convenience method. For more information about a mapping see the
    /// [`translate`](MapperAllSizes::translate) method.
    #[inline]
    fn translate_addr(&self, addr: VirtAddr) -> Option<PhysAddr> {
        match self.translate(addr) {
            TranslateResult::PageNotMapped | TranslateResult::InvalidFrameAddress(_) => None,
            TranslateResult::Frame4KiB { frame, offset } => Some(frame.start_address() + offset),
            TranslateResult::Frame2MiB { frame, offset } => Some(frame.start_address() + offset),
            TranslateResult::Frame1GiB { frame, offset } => Some(frame.start_address() + offset),
        }
    }
}

/// The return value of the [`MapperAllSizes::translate`] function.
///
/// If the given address has a valid mapping, a `Frame4KiB`, `Frame2MiB`, or `Frame1GiB` variant
/// is returned, depending on the size of the mapped page. The remaining variants indicate errors.
#[derive(Debug)]
pub enum TranslateResult {
    /// The page is mapped to a physical frame of size 4KiB.
    Frame4KiB {
        /// The mapped frame.
        frame: PhysFrame<Size4KiB>,
        /// The offset whithin the mapped frame.
        offset: u64,
    },
    /// The page is mapped to a physical frame of size 2MiB.
    Frame2MiB {
        /// The mapped frame.
        frame: PhysFrame<Size2MiB>,
        /// The offset whithin the mapped frame.
        offset: u64,
    },
    /// The page is mapped to a physical frame of size 2MiB.
    Frame1GiB {
        /// The mapped frame.
        frame: PhysFrame<Size1GiB>,
        /// The offset whithin the mapped frame.
        offset: u64,
    },
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// The page table entry for the given page points to an invalid physical address.
    InvalidFrameAddress(PhysAddr),
}

/// A trait for common page table operations on pages of size `S`.
pub trait Mapper<S: PageSize> {
    /// Creates a new mapping in the page table.
    ///
    /// This function might need additional physical frames to create new page tables. These
    /// frames are allocated from the `allocator` argument. At most three frames are required.
    ///
    /// This function is unsafe because the caller must guarantee that passed `frame` is
    /// unused, i.e. not used for any other mappings.
    unsafe fn map_to<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
    where
        Self: Sized,
        A: FrameAllocator<Size4KiB>;

    /// Removes a mapping from the page table and returns the frame that used to be mapped.
    ///
    /// Note that no page tables or pages are deallocated.
    fn unmap(&mut self, page: Page<S>) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>;

    /// Updates the flags of an existing mapping.
    fn update_flags(
        &mut self,
        page: Page<S>,
        flags: PageTableFlags,
    ) -> Result<MapperFlush<S>, FlagUpdateError>;

    /// Return the frame that the specified page is mapped to.
    ///
    /// This function assumes that the page is mapped to a frame of size `S` and returns an
    /// error otherwise.
    fn translate_page(&self, page: Page<S>) -> Result<PhysFrame<S>, TranslateError>;

    /// Maps the given frame to the virtual page with the same address.
    ///
    /// ## Safety
    ///
    /// This function is unsafe because the caller must guarantee that the passed `frame` is
    /// unused, i.e. not used for any other mappings.
    #[inline]
    unsafe fn identity_map<A>(
        &mut self,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
    where
        Self: Sized,
        A: FrameAllocator<Size4KiB>,
        S: PageSize,
        Self: Mapper<S>,
    {
        let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
        self.map_to(page, frame, flags, frame_allocator)
    }
}

/// This type represents a page whose mapping has changed in the page table.
///
/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs
/// to be flushed from the TLB before it's accessed. This type is returned from function that
/// change the mapping of a page to ensure that the TLB flush is not forgotten.
#[derive(Debug)]
#[must_use = "Page Table changes must be flushed or ignored."]
pub struct MapperFlush<S: PageSize>(Page<S>);

impl<S: PageSize> MapperFlush<S> {
    /// Create a new flush promise
    fn new(page: Page<S>) -> Self {
        MapperFlush(page)
    }

    /// Flush the page from the TLB to ensure that the newest mapping is used.
    #[cfg(target_arch = "x86_64")]
    #[inline]
    pub fn flush(self) {
        crate::instructions::tlb::flush(self.0.start_address());
    }

    /// Don't flush the TLB and silence the “must be used” warning.
    #[inline]
    pub fn ignore(self) {}
}

/// This error is returned from `map_to` and similar methods.
#[derive(Debug)]
pub enum MapToError<S: PageSize> {
    /// An additional frame was needed for the mapping process, but the frame allocator
    /// returned `None`.
    FrameAllocationFailed,
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of an already mapped huge page.
    ParentEntryHugePage,
    /// The given page is already mapped to a physical frame.
    PageAlreadyMapped(PhysFrame<S>),
}

/// An error indicating that an `unmap` call failed.
#[derive(Debug)]
pub enum UnmapError {
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of a huge page and can't be freed individually.
    ParentEntryHugePage,
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// The page table entry for the given page points to an invalid physical address.
    InvalidFrameAddress(PhysAddr),
}

/// An error indicating that an `update_flags` call failed.
#[derive(Debug)]
pub enum FlagUpdateError {
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of a huge page and can't be freed individually.
    ParentEntryHugePage,
}

/// An error indicating that an `translate` call failed.
#[derive(Debug)]
pub enum TranslateError {
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of a huge page and can't be freed individually.
    ParentEntryHugePage,
    /// The page table entry for the given page points to an invalid physical address.
    InvalidFrameAddress(PhysAddr),
}

static _ASSERT_OBJECT_SAFE: Option<&(dyn MapperAllSizes + Sync)> = None;
<commit_msg>Add more extensive docs on safety to `map_to`<commit_after>//! Abstractions for reading and modifying the mapping of pages.

pub use self::mapped_page_table::{MappedPageTable, PhysToVirt};
#[cfg(target_arch = "x86_64")]
pub use self::{offset_page_table::OffsetPageTable, recursive_page_table::RecursivePageTable};

use crate::structures::paging::{
    frame_alloc::FrameAllocator, page_table::PageTableFlags, Page, PageSize, PhysFrame, Size1GiB,
    Size2MiB, Size4KiB,
};
use crate::{PhysAddr, VirtAddr};

mod mapped_page_table;
mod offset_page_table;
mod recursive_page_table;

/// This trait defines page table operations that work for all page sizes of the x86_64
/// architecture.
pub trait MapperAllSizes: Mapper<Size4KiB> + Mapper<Size2MiB> + Mapper<Size1GiB> {
    /// Return the frame that the given virtual address is mapped to and the offset within that
    /// frame.
    ///
    /// If the given address has a valid mapping, the mapped frame and the offset within that
    /// frame is returned. Otherwise an error value is returned.
    ///
    /// This function works with huge pages of all sizes.
    fn translate(&self, addr: VirtAddr) -> TranslateResult;

    /// Translates the given virtual address to the physical address that it maps to.
    ///
    /// Returns `None` if there is no valid mapping for the given address.
    ///
    /// This is a convenience method. For more information about a mapping see the
    /// [`translate`](MapperAllSizes::translate) method.
    #[inline]
    fn translate_addr(&self, addr: VirtAddr) -> Option<PhysAddr> {
        match self.translate(addr) {
            TranslateResult::PageNotMapped | TranslateResult::InvalidFrameAddress(_) => None,
            TranslateResult::Frame4KiB { frame, offset } => Some(frame.start_address() + offset),
            TranslateResult::Frame2MiB { frame, offset } => Some(frame.start_address() + offset),
            TranslateResult::Frame1GiB { frame, offset } => Some(frame.start_address() + offset),
        }
    }
}

/// The return value of the [`MapperAllSizes::translate`] function.
///
/// If the given address has a valid mapping, a `Frame4KiB`, `Frame2MiB`, or `Frame1GiB` variant
/// is returned, depending on the size of the mapped page. The remaining variants indicate errors.
#[derive(Debug)]
pub enum TranslateResult {
    /// The page is mapped to a physical frame of size 4KiB.
    Frame4KiB {
        /// The mapped frame.
        frame: PhysFrame<Size4KiB>,
        /// The offset whithin the mapped frame.
        offset: u64,
    },
    /// The page is mapped to a physical frame of size 2MiB.
    Frame2MiB {
        /// The mapped frame.
        frame: PhysFrame<Size2MiB>,
        /// The offset whithin the mapped frame.
        offset: u64,
    },
    /// The page is mapped to a physical frame of size 2MiB.
    Frame1GiB {
        /// The mapped frame.
        frame: PhysFrame<Size1GiB>,
        /// The offset whithin the mapped frame.
        offset: u64,
    },
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// The page table entry for the given page points to an invalid physical address.
    InvalidFrameAddress(PhysAddr),
}

/// A trait for common page table operations on pages of size `S`.
pub trait Mapper<S: PageSize> {
    /// Creates a new mapping in the page table.
    ///
    /// This function might need additional physical frames to create new page tables. These
    /// frames are allocated from the `allocator` argument. At most three frames are required.
    ///
    /// ## Safety
    ///
    /// Creating page table mappings is a fundamentally unsafe operation because
    /// there are various ways to break memory safety through it. For example,
    /// re-mapping an in-use page to a different frame changes and invalidates
    /// all values stored in that page, resulting in undefined behavior on the
    /// next use.
    ///
    /// The caller must ensure that no undefined behavior or memory safety
    /// violations can occur through the new mapping. Among other things, the
    /// caller must prevent the following:
    ///
    /// - Aliasing of `&mut` references, i.e. two `&mut` references that point to
    ///   the same physical address. This is undefined behavior in Rust.
    ///     - This can be ensured by mapping each page to an individual physical
    ///       frame that is not mapped anywhere else.
    /// - Creating uninitalized or invalid values: Rust requires that all values
    ///   have a correct memory layout. For example, a `bool` must be either a 0
    ///   or a 1 in memory, but not a 3 or 4. An exception is the `MaybeUninit`
    ///   wrapper type, which abstracts over possibly uninitialized memory.
    ///     - This is only a problem when re-mapping pages to different physical
    ///       frames. Mapping a page that is not in use yet is fine.
    ///
    /// Special care must be taken when sharing pages with other address spaces,
    /// e.g. by setting the `GLOBAL` flag. For example, a global mapping must be
    /// the same in all address spaces, otherwise undefined behavior can occur
    /// because of TLB races. It's worth noting that all the above requirements
    /// also apply to shared mappings, including the aliasing requirements.
    unsafe fn map_to<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
    where
        Self: Sized,
        A: FrameAllocator<Size4KiB>;

    /// Removes a mapping from the page table and returns the frame that used to be mapped.
    ///
    /// Note that no page tables or pages are deallocated.
    fn unmap(&mut self, page: Page<S>) -> Result<(PhysFrame<S>, MapperFlush<S>), UnmapError>;

    /// Updates the flags of an existing mapping.
    fn update_flags(
        &mut self,
        page: Page<S>,
        flags: PageTableFlags,
    ) -> Result<MapperFlush<S>, FlagUpdateError>;

    /// Return the frame that the specified page is mapped to.
    ///
    /// This function assumes that the page is mapped to a frame of size `S` and returns an
    /// error otherwise.
    fn translate_page(&self, page: Page<S>) -> Result<PhysFrame<S>, TranslateError>;

    /// Maps the given frame to the virtual page with the same address.
    ///
    /// ## Safety
    ///
    /// This is a convencience function that invokes [`map_to`] internally, so
    /// all safety requirements of it also apply for this function.
    #[inline]
    unsafe fn identity_map<A>(
        &mut self,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        frame_allocator: &mut A,
    ) -> Result<MapperFlush<S>, MapToError<S>>
    where
        Self: Sized,
        A: FrameAllocator<Size4KiB>,
        S: PageSize,
        Self: Mapper<S>,
    {
        let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
        self.map_to(page, frame, flags, frame_allocator)
    }
}

/// This type represents a page whose mapping has changed in the page table.
///
/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs
/// to be flushed from the TLB before it's accessed. This type is returned from function that
/// change the mapping of a page to ensure that the TLB flush is not forgotten.
#[derive(Debug)]
#[must_use = "Page Table changes must be flushed or ignored."]
pub struct MapperFlush<S: PageSize>(Page<S>);

impl<S: PageSize> MapperFlush<S> {
    /// Create a new flush promise
    fn new(page: Page<S>) -> Self {
        MapperFlush(page)
    }

    /// Flush the page from the TLB to ensure that the newest mapping is used.
    #[cfg(target_arch = "x86_64")]
    #[inline]
    pub fn flush(self) {
        crate::instructions::tlb::flush(self.0.start_address());
    }

    /// Don't flush the TLB and silence the “must be used” warning.
    #[inline]
    pub fn ignore(self) {}
}

/// This error is returned from `map_to` and similar methods.
#[derive(Debug)]
pub enum MapToError<S: PageSize> {
    /// An additional frame was needed for the mapping process, but the frame allocator
    /// returned `None`.
    FrameAllocationFailed,
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of an already mapped huge page.
    ParentEntryHugePage,
    /// The given page is already mapped to a physical frame.
    PageAlreadyMapped(PhysFrame<S>),
}

/// An error indicating that an `unmap` call failed.
#[derive(Debug)]
pub enum UnmapError {
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of a huge page and can't be freed individually.
    ParentEntryHugePage,
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// The page table entry for the given page points to an invalid physical address.
    InvalidFrameAddress(PhysAddr),
}

/// An error indicating that an `update_flags` call failed.
#[derive(Debug)]
pub enum FlagUpdateError {
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of a huge page and can't be freed individually.
    ParentEntryHugePage,
}

/// An error indicating that an `translate` call failed.
#[derive(Debug)]
pub enum TranslateError {
    /// The given page is not mapped to a physical frame.
    PageNotMapped,
    /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
    /// given page is part of a huge page and can't be freed individually.
    ParentEntryHugePage,
    /// The page table entry for the given page points to an invalid physical address.
    InvalidFrameAddress(PhysAddr),
}

static _ASSERT_OBJECT_SAFE: Option<&(dyn MapperAllSizes + Sync)> = None;
<|endoftext|>


<commit_before>//! Types for the [`m.room.join_rules`] event.
//!
//! [`m.room.join_rules`]: https://spec.matrix.org/v1.1/client-server-api/#mroomjoin_rules

use ruma_events_macros::EventContent;
#[cfg(feature = "unstable-spec")]
use ruma_identifiers::RoomId;
use ruma_serde::from_raw_json_value;
use serde::{
    de::{Deserializer, Error},
    Deserialize, Serialize,
};
use serde_json::value::RawValue as RawJsonValue;
#[cfg(feature = "unstable-spec")]
use serde_json::Value as JsonValue;
use std::borrow::Cow;
#[cfg(feature = "unstable-spec")]
use std::collections::BTreeMap;

use crate::PrivOwnedStr;

/// The content of an `m.room.join_rules` event.
///
/// Describes how users are allowed to join the room.
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State)]
pub struct RoomJoinRulesEventContent {
    /// The type of rules used for users wishing to join this room.
    #[ruma_event(skip_redaction)]
    #[serde(flatten)]
    pub join_rule: JoinRule,
}

impl RoomJoinRulesEventContent {
    /// Creates a new `RoomJoinRulesEventContent` with the given rule.
    pub fn new(join_rule: JoinRule) -> Self {
        Self { join_rule }
    }

    /// Creates a new `RoomJoinRulesEventContent` with the restricted rule and the given set of
    /// allow rules.
    #[cfg(feature = "unstable-spec")]
    pub fn restricted(allow: Vec<AllowRule>) -> Self {
        Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
    }
}

impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let join_rule = JoinRule::deserialize(deserializer)?;
        Ok(RoomJoinRulesEventContent { join_rule })
    }
}

/// The rule used for users wishing to join this room.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "join_rule")]
pub enum JoinRule {
    /// A user who wishes to join the room must first receive an invite to the room from someone
    /// already inside of the room.
    #[serde(rename = "invite")]
    Invite,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "knock")]
    Knock,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "private")]
    Private,

    /// Users can join the room if they are invited, or if they meet any of the conditions
    /// described in a set of [`AllowRule`]s.
    #[cfg(feature = "unstable-spec")]
    #[serde(rename = "restricted")]
    Restricted(Restricted),

    /// Anyone can join the room without any prior action.
    #[serde(rename = "public")]
    Public,

    #[doc(hidden)]
    #[serde(skip_serializing)]
    _Custom(PrivOwnedStr),
}

impl JoinRule {
    /// Returns the string name of this `JoinRule`
    pub fn as_str(&self) -> &str {
        match self {
            JoinRule::Invite => "invite",
            JoinRule::Knock => "knock",
            JoinRule::Private => "private",
            #[cfg(feature = "unstable-spec")]
            JoinRule::Restricted(_) => "restricted",
            JoinRule::Public => "public",
            JoinRule::_Custom(rule) => &rule.0,
        }
    }
}

impl<'de> Deserialize<'de> for JoinRule {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        #[derive(Deserialize)]
        struct ExtractType<'a> {
            join_rule: Option<Cow<'a, str>>,
        }

        let join_rule = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .join_rule
            .ok_or_else(|| D::Error::missing_field("join_rule"))?;

        match join_rule.as_ref() {
            "invite" => Ok(Self::Invite),
            "knock" => Ok(Self::Knock),
            "private" => Ok(Self::Private),
            #[cfg(feature = "unstable-spec")]
            "restricted" => from_raw_json_value(&json).map(Self::Restricted),
            "public" => Ok(Self::Public),
            _ => Ok(Self::_Custom(PrivOwnedStr(join_rule.into()))),
        }
    }
}

/// Configuration of the `Restricted` join rule.
#[cfg(feature = "unstable-spec")]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Restricted {
    /// Allow rules which describe conditions that allow joining a room.
    allow: Vec<AllowRule>,
}

#[cfg(feature = "unstable-spec")]
impl Restricted {
    /// Constructs a new rule set for restricted rooms with the given rules.
    pub fn new(allow: Vec<AllowRule>) -> Self {
        Self { allow }
    }
}

/// An allow rule which defines a condition that allows joining a room.
#[cfg(feature = "unstable-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type")]
pub enum AllowRule {
    /// Joining is allowed if a user is already a member of the room with the id `room_id`.
    #[serde(rename = "m.room_membership")]
    RoomMembership(RoomMembership),

    #[doc(hidden)]
    _Custom(CustomAllowRule),
}

#[cfg(feature = "unstable-spec")]
impl AllowRule {
    /// Constructs an `AllowRule` with membership of the room with the given id as its predicate.
    pub fn room_membership(room_id: Box<RoomId>) -> Self {
        Self::RoomMembership(RoomMembership::new(room_id))
    }
}

/// Allow rule which grants permission to join based on the membership of another room.
#[cfg(feature = "unstable-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomMembership {
    /// The id of the room which being a member of grants permission to join another room.
    pub room_id: Box<RoomId>,
}

#[cfg(feature = "unstable-spec")]
impl RoomMembership {
    /// Constructs a new room membership rule for the given room id.
    pub fn new(room_id: Box<RoomId>) -> Self {
        Self { room_id }
    }
}

#[cfg(feature = "unstable-spec")]
#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CustomAllowRule {
    #[serde(rename = "type")]
    rule_type: String,
    #[serde(flatten)]
    extra: BTreeMap<String, JsonValue>,
}

#[cfg(feature = "unstable-spec")]
impl<'de> Deserialize<'de> for AllowRule {
    fn deserialize<D>(deserializer: D) -> Result<AllowRule, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        // Extracts the `type` value.
        #[derive(Deserialize)]
        struct ExtractType<'a> {
            #[serde(borrow, rename = "type")]
            rule_type: Option<Cow<'a, str>>,
        }

        // Get the value of `type` if present.
        let rule_type = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .rule_type;

        match rule_type.as_deref() {
            Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership),
            Some(_) => from_raw_json_value(&json).map(Self::_Custom),
            None => Err(D::Error::missing_field("type")),
        }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    #[cfg(feature = "unstable-spec")]
    use ruma_identifiers::room_id;

    #[cfg(feature = "unstable-spec")]
    use super::AllowRule;
    use super::{JoinRule, RoomJoinRulesEventContent, SyncRoomJoinRulesEvent};

    #[test]
    fn deserialize() {
        let json = r#"{"join_rule": "public"}"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
    }

    #[cfg(feature = "unstable-spec")]
    #[test]
    fn deserialize_restricted() {
        let json = r#"{
            "join_rule": "restricted",
            "allow": [
                {
                    "type": "m.room_membership",
                    "room_id": "!mods:example.org"
                },
                {
                    "type": "m.room_membership",
                    "room_id": "!users:example.org"
                }
            ]
        }"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        match event.join_rule {
            JoinRule::Restricted(restricted) => assert_eq!(
                restricted.allow,
                &[
                    AllowRule::room_membership(room_id!("!mods:example.org").to_owned()),
                    AllowRule::room_membership(room_id!("!users:example.org").to_owned())
                ]
            ),
            rule => panic!("Deserialized to wrong variant: {:?}", rule),
        }
    }

    #[test]
    fn deserialize_restricted_event() {
        let json = r#"{
            "type": "m.room.join_rules",
            "sender": "@admin:community.rs",
            "content": {
                "join_rule": "restricted",
                "allow":[
                    { "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
                ]
            },
            "state_key": "",
            "origin_server_ts":1630508835342,
            "unsigned": {
                "age":4165521871
            },
            "event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
        }"#;

        assert_matches!(serde_json::from_str::<SyncRoomJoinRulesEvent>(json), Ok(_));
    }
}
<commit_msg>events: Fix missing feature-gate on import<commit_after>//! Types for the [`m.room.join_rules`] event.
//!
//! [`m.room.join_rules`]: https://spec.matrix.org/v1.1/client-server-api/#mroomjoin_rules

use ruma_events_macros::EventContent;
#[cfg(feature = "unstable-spec")]
use ruma_identifiers::RoomId;
#[cfg(feature = "unstable-spec")]
use ruma_serde::from_raw_json_value;
use serde::{
    de::{Deserializer, Error},
    Deserialize, Serialize,
};
use serde_json::value::RawValue as RawJsonValue;
#[cfg(feature = "unstable-spec")]
use serde_json::Value as JsonValue;
use std::borrow::Cow;
#[cfg(feature = "unstable-spec")]
use std::collections::BTreeMap;

use crate::PrivOwnedStr;

/// The content of an `m.room.join_rules` event.
///
/// Describes how users are allowed to join the room.
#[derive(Clone, Debug, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.room.join_rules", kind = State)]
pub struct RoomJoinRulesEventContent {
    /// The type of rules used for users wishing to join this room.
    #[ruma_event(skip_redaction)]
    #[serde(flatten)]
    pub join_rule: JoinRule,
}

impl RoomJoinRulesEventContent {
    /// Creates a new `RoomJoinRulesEventContent` with the given rule.
    pub fn new(join_rule: JoinRule) -> Self {
        Self { join_rule }
    }

    /// Creates a new `RoomJoinRulesEventContent` with the restricted rule and the given set of
    /// allow rules.
    #[cfg(feature = "unstable-spec")]
    pub fn restricted(allow: Vec<AllowRule>) -> Self {
        Self { join_rule: JoinRule::Restricted(Restricted::new(allow)) }
    }
}

impl<'de> Deserialize<'de> for RoomJoinRulesEventContent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let join_rule = JoinRule::deserialize(deserializer)?;
        Ok(RoomJoinRulesEventContent { join_rule })
    }
}

/// The rule used for users wishing to join this room.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "join_rule")]
pub enum JoinRule {
    /// A user who wishes to join the room must first receive an invite to the room from someone
    /// already inside of the room.
    #[serde(rename = "invite")]
    Invite,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "knock")]
    Knock,

    /// Reserved but not yet implemented by the Matrix specification.
    #[serde(rename = "private")]
    Private,

    /// Users can join the room if they are invited, or if they meet any of the conditions
    /// described in a set of [`AllowRule`]s.
    #[cfg(feature = "unstable-spec")]
    #[serde(rename = "restricted")]
    Restricted(Restricted),

    /// Anyone can join the room without any prior action.
    #[serde(rename = "public")]
    Public,

    #[doc(hidden)]
    #[serde(skip_serializing)]
    _Custom(PrivOwnedStr),
}

impl JoinRule {
    /// Returns the string name of this `JoinRule`
    pub fn as_str(&self) -> &str {
        match self {
            JoinRule::Invite => "invite",
            JoinRule::Knock => "knock",
            JoinRule::Private => "private",
            #[cfg(feature = "unstable-spec")]
            JoinRule::Restricted(_) => "restricted",
            JoinRule::Public => "public",
            JoinRule::_Custom(rule) => &rule.0,
        }
    }
}

impl<'de> Deserialize<'de> for JoinRule {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        #[derive(Deserialize)]
        struct ExtractType<'a> {
            join_rule: Option<Cow<'a, str>>,
        }

        let join_rule = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .join_rule
            .ok_or_else(|| D::Error::missing_field("join_rule"))?;

        match join_rule.as_ref() {
            "invite" => Ok(Self::Invite),
            "knock" => Ok(Self::Knock),
            "private" => Ok(Self::Private),
            #[cfg(feature = "unstable-spec")]
            "restricted" => from_raw_json_value(&json).map(Self::Restricted),
            "public" => Ok(Self::Public),
            _ => Ok(Self::_Custom(PrivOwnedStr(join_rule.into()))),
        }
    }
}

/// Configuration of the `Restricted` join rule.
#[cfg(feature = "unstable-spec")]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Restricted {
    /// Allow rules which describe conditions that allow joining a room.
    allow: Vec<AllowRule>,
}

#[cfg(feature = "unstable-spec")]
impl Restricted {
    /// Constructs a new rule set for restricted rooms with the given rules.
    pub fn new(allow: Vec<AllowRule>) -> Self {
        Self { allow }
    }
}

/// An allow rule which defines a condition that allows joining a room.
#[cfg(feature = "unstable-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type")]
pub enum AllowRule {
    /// Joining is allowed if a user is already a member of the room with the id `room_id`.
    #[serde(rename = "m.room_membership")]
    RoomMembership(RoomMembership),

    #[doc(hidden)]
    _Custom(CustomAllowRule),
}

#[cfg(feature = "unstable-spec")]
impl AllowRule {
    /// Constructs an `AllowRule` with membership of the room with the given id as its predicate.
    pub fn room_membership(room_id: Box<RoomId>) -> Self {
        Self::RoomMembership(RoomMembership::new(room_id))
    }
}

/// Allow rule which grants permission to join based on the membership of another room.
#[cfg(feature = "unstable-spec")]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomMembership {
    /// The id of the room which being a member of grants permission to join another room.
    pub room_id: Box<RoomId>,
}

#[cfg(feature = "unstable-spec")]
impl RoomMembership {
    /// Constructs a new room membership rule for the given room id.
    pub fn new(room_id: Box<RoomId>) -> Self {
        Self { room_id }
    }
}

#[cfg(feature = "unstable-spec")]
#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CustomAllowRule {
    #[serde(rename = "type")]
    rule_type: String,
    #[serde(flatten)]
    extra: BTreeMap<String, JsonValue>,
}

#[cfg(feature = "unstable-spec")]
impl<'de> Deserialize<'de> for AllowRule {
    fn deserialize<D>(deserializer: D) -> Result<AllowRule, D::Error>
    where
        D: Deserializer<'de>,
    {
        let json: Box<RawJsonValue> = Box::deserialize(deserializer)?;

        // Extracts the `type` value.
        #[derive(Deserialize)]
        struct ExtractType<'a> {
            #[serde(borrow, rename = "type")]
            rule_type: Option<Cow<'a, str>>,
        }

        // Get the value of `type` if present.
        let rule_type = serde_json::from_str::<ExtractType<'_>>(json.get())
            .map_err(serde::de::Error::custom)?
            .rule_type;

        match rule_type.as_deref() {
            Some("m.room_membership") => from_raw_json_value(&json).map(Self::RoomMembership),
            Some(_) => from_raw_json_value(&json).map(Self::_Custom),
            None => Err(D::Error::missing_field("type")),
        }
    }
}

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    #[cfg(feature = "unstable-spec")]
    use ruma_identifiers::room_id;

    #[cfg(feature = "unstable-spec")]
    use super::AllowRule;
    use super::{JoinRule, RoomJoinRulesEventContent, SyncRoomJoinRulesEvent};

    #[test]
    fn deserialize() {
        let json = r#"{"join_rule": "public"}"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        assert_matches!(event, RoomJoinRulesEventContent { join_rule: JoinRule::Public });
    }

    #[cfg(feature = "unstable-spec")]
    #[test]
    fn deserialize_restricted() {
        let json = r#"{
            "join_rule": "restricted",
            "allow": [
                {
                    "type": "m.room_membership",
                    "room_id": "!mods:example.org"
                },
                {
                    "type": "m.room_membership",
                    "room_id": "!users:example.org"
                }
            ]
        }"#;
        let event: RoomJoinRulesEventContent = serde_json::from_str(json).unwrap();
        match event.join_rule {
            JoinRule::Restricted(restricted) => assert_eq!(
                restricted.allow,
                &[
                    AllowRule::room_membership(room_id!("!mods:example.org").to_owned()),
                    AllowRule::room_membership(room_id!("!users:example.org").to_owned())
                ]
            ),
            rule => panic!("Deserialized to wrong variant: {:?}", rule),
        }
    }

    #[test]
    fn deserialize_restricted_event() {
        let json = r#"{
            "type": "m.room.join_rules",
            "sender": "@admin:community.rs",
            "content": {
                "join_rule": "restricted",
                "allow":[
                    { "type": "m.room_membership","room_id": "!KqeUnzmXPIhHRaWMTs:mccarty.io" }
                ]
            },
            "state_key": "",
            "origin_server_ts":1630508835342,
            "unsigned": {
                "age":4165521871
            },
            "event_id": "$0ACb9KSPlT3al3kikyRYvFhMqXPP9ZcQOBrsdIuh58U"
        }"#;

        assert_matches!(serde_json::from_str::<SyncRoomJoinRulesEvent>(json), Ok(_));
    }
}
<|endoftext|>