<commit_before>// FIXME: Replace these examples with executable tests
//! Traits related to relationships between multiple tables.
//!
//! **Note: This feature is under active development, and we are seeking feedback on the APIs that
//! have been released. Please feel free to [open issues][open-issue], or join [our chat][gitter]
//! to provide feedback.**
//!
//! [open-issue]: https://github.com/diesel-rs/diesel/issues/new
//! [gitter]: https://gitter.im/diesel-rs/diesel
//!
//! Note: The derives in this guide are provided by `diesel_codegen`. Make sure you have
//! `#[macro_use] extern crate diesel_codegen;` at the root of your crate.
//!
//! Associations in Diesel are bidirectional, but primarily focus on the child-to-parent
//! relationship. You can declare an association between two records with
//! `#[belongs_to]`.
//!
//! ```rust
//! // You need to have the table definitions from `infer_schema!` or `table!` in scope to
//! // derive Identifiable.
//! # #[macro_use] extern crate diesel;
//! # #[macro_use] extern crate diesel_codegen;
//! # include!("src/doctest_setup.rs");
//! use schema::{posts, users};
//!
//! #[derive(Identifiable, Queryable)]
//! pub struct User {
//!     id: i32,
//!     name: String,
//! }
//!
//! # #[derive(Debug, PartialEq)]
//! #[derive(Identifiable, Queryable, Associations)]
//! #[belongs_to(User)]
//! pub struct Post {
//!     id: i32,
//!     user_id: i32,
//!     title: String,
//! }
//!
//! # fn main() {
//! # let connection = establish_connection();
//! # let user = users::table.find(2).get_result::<User>(&connection).unwrap();
//! # let posts = Post::belonging_to(&user).load::<Post>(&connection);
//! # assert_eq!(posts, Ok(vec![Post { id: 3, user_id: 2, title: "My first post too".to_owned() }]));
//! # }
//! ```
//!
//! Note that in addition to the `#[has_many]` annotation, we also need to
//! `#[derive(Associations)]`
//!
//! `#[belongs_to]` is given the name of the struct that represents the parent. Both types
//! must implement the [`Identifiable`][identifiable] trait. The struct or table referenced in your
//! association has to be in scope, so you'll need `use schema::posts` or similar to bring the
//! table into scope, and `use some_module::User` if `User` were in a different module.
//!
//! [Identifiable]: trait.Identifiable.html
//!
//! If the name of your foreign key doesn't follow the convention `tablename_id`, you can specify a
//! custom one `#[belongs_to]` by adding a `foreign_key` argument to the
//! attribute like so `#[belongs_to(Foo, foreign_key="mykey")]`.
//!
//! Once the associations are defined, you can join between the two tables using the
//! [`inner_join`][inner-join] or [`left_outer_join`][left-outer-join].
//!
//! [inner-join]: /diesel/query_source/trait.Table.html#method.inner_join
//! [left-outer-join]: /diesel/query_source/trait.Table.html#method.left_outer_join
//!
//! ```ignore
//! let data: Vec<(User, Post)> = users::table.inner_join(posts::table).load(&connection);
//! ```
//!
//! Note: Due to language limitations, only two tables can be joined per query. This will change in
//! the future.
//!
//! Typically however, queries are loaded in multiple queries. For most datasets, the reduced
//! amount of duplicated information sent over the wire saves more time than the extra round trip
//! costs us. You can load the children for a single parent using the
//! [`belonging_to`][belonging-to]
//!
//! [belonging-to]: /diesel/prelude/trait.BelongingToDsl.html#tymethod.belonging_to
//!
//! ```ignore
//! let user = try!(users::find(1).first(&connection));
//! let posts = Post::belonging_to(&user).load(&connection);
//! ```
//!
//! If you're coming from other ORMs, you'll notice that this design is quite different from most.
//! There you would have an instance method on the parent, or have the children stored somewhere on
//! the posts. This design leads to many problems, including [N+1 query
//! bugs][load-your-entire-database-into-memory-lol], and runtime errors when accessing an
//! association that isn't there.
//!
//! [load-your-entire-database-into-memory-lol]: http://stackoverflow.com/q/97197/1254484
//!
//! In Diesel, data and its associations are considered to be separate. If you want to pass around
//! a user and all of its posts, that type is `(User, Vec<Post>)`.
//!
//! Next lets look at how to load the children for more than one parent record.
//! [`belonging_to`][belonging-to] can be used to load the data, but we'll also need to group it
//! with its parents. For this we use an additional method [`grouped_by`][grouped-by]
//!
//! [grouped-by]: trait.GroupedBy.html#tymethod.grouped_by
//!
//! ```ignore
//! fn first_twenty_users_and_their_posts(conn: &PgConnection) -> QueryResult<Vec<(User, Vec<Post>)>> {
//!     let users = try!(users::limit(20).load::<User>(conn));
//!     let posts = try!(Post::belonging_to(&users).load::<Post>(conn));
//!     let grouped_posts = posts.grouped_by(&users);
//!     users.into_iter().zip(grouped_posts).collect()
//! }
//! ```
//!
//! [`grouped_by`][grouped-by] takes a `Vec<Child>` and a `Vec<Parent>` and returns a
//! `Vec<Vec<Child>>` where the index of the children matches the index of the parent they belong
//! to. Or to put it another way, it returns them in an order ready to be `zip`ed with the parents. You
//! can do this multiple times. For example, if you wanted to load the comments for all the posts
//! as well, you could do this: (explicit type annotations have been added for documentation
//! purposes)
//!
//! ```ignore
//! let posts: Vec<Post> = try!(Post::belonging_to(&users).load());
//! let comments: Vec<Comment> = try!(Comment::belonging_to(&posts).load());
//! let comments: Vec<Vec<Comment>> = comments.grouped_by(&posts);
//! let posts_and_comments: Vec<Vec<(Post, Vec<Comment>)>> = posts.into_iter().zip(comments).grouped_by(&users);
//! let result: Vec<(User, Vec<(Post, Vec<Comment>)>)> = users.into_iter().zip(posts_and_comments).collect();
//! ```
//!
//! And that's it. This module will be expanded in the future with more complex joins, and the
//! ability to define "through" associations (e.g. load all the comments left on any posts written
//! by a user in a single query). However, the goal is to provide simple building blocks which can
//! be used to construct the complex behavior applications need.
mod belongs_to;

use std::hash::Hash;

use query_source::Table;

pub use self::belongs_to::{BelongsTo, GroupedBy};

pub trait HasTable {
    type Table: Table;

    fn table() -> Self::Table;
}

impl<'a, T: HasTable> HasTable for &'a T {
    type Table = T::Table;

    fn table() -> Self::Table {
        T::table()
    }
}

/// Represents a struct which can be identified on a single table in the
/// database. This must be implemented to use associations, and some features of
/// updating. This trait is usually implemented on a reference to a struct, not
/// the struct itself.
///
/// ### Deriving
///
/// This trait can be automatically derived using `diesel_codegen` by adding
/// `#[derive(Identifiable)]` to your struct. The primary key will be assumed to be a field and
/// column called `id`. If it's not, you can annotate your structure with `#[primary_key(your_id)]`
/// or `#[primary_key(your_id, second_id)]`. By default the table will be assumed to be the plural
/// form of the struct name (using *very* dumb pluralization -- it just adds an `s` at the end). If
/// your table name differs from that convention, or requires complex pluralization, it can be
/// specified using `#[table_name = "some_table_name"]`. The inferred table name is considered
/// public API and will never change without a major version bump.
pub trait Identifiable: HasTable {
    type Id: Hash + Eq;

    fn id(self) -> Self::Id;
}
<commit_msg>Minor doc fixes<commit_after>// FIXME: Replace these examples with executable tests
//! Traits related to relationships between multiple tables.
//!
//! **Note: This feature is under active development, and we are seeking feedback on the APIs that
//! have been released. Please feel free to [open issues][open-issue], or join [our chat][gitter]
//! to provide feedback.**
//!
//! [open-issue]: https://github.com/diesel-rs/diesel/issues/new
//! [gitter]: https://gitter.im/diesel-rs/diesel
//!
//! Note: The derives in this guide are provided by `diesel_codegen`. Make sure you have
//! `#[macro_use] extern crate diesel_codegen;` at the root of your crate.
//!
//! Associations in Diesel are bidirectional, but primarily focus on the child-to-parent
//! relationship. You can declare an association between two records with
//! `#[belongs_to]`.
//!
//! ```rust
//! // You need to have the table definitions from `infer_schema!` or `table!` in scope to
//! // derive Identifiable.
//! # #[macro_use] extern crate diesel;
//! # #[macro_use] extern crate diesel_codegen;
//! # include!("src/doctest_setup.rs");
//! use schema::{posts, users};
//!
//! #[derive(Identifiable, Queryable)]
//! pub struct User {
//!     id: i32,
//!     name: String,
//! }
//!
//! # #[derive(Debug, PartialEq)]
//! #[derive(Identifiable, Queryable, Associations)]
//! #[belongs_to(User)]
//! pub struct Post {
//!     id: i32,
//!     user_id: i32,
//!     title: String,
//! }
//!
//! # fn main() {
//! # let connection = establish_connection();
//! # let user = users::table.find(2).get_result::<User>(&connection).unwrap();
//! # let posts = Post::belonging_to(&user).load::<Post>(&connection);
//! # assert_eq!(posts, Ok(vec![Post { id: 3, user_id: 2, title: "My first post too".to_owned() }]));
//! # }
//! ```
//!
//! Note that in addition to the `#[belongs_to]` annotation, we also need to
//! `#[derive(Associations)]`
//!
//! `#[belongs_to]` is given the name of the struct that represents the parent. Both types
//! must implement the [`Identifiable`][identifiable] trait. The struct or table referenced in your
//! association has to be in scope, so you'll need `use schema::posts` or similar to bring the
//! table into scope, and `use some_module::User` if `User` were in a different module.
//!
//! [Identifiable]: trait.Identifiable.html
//!
//! If the name of your foreign key doesn't follow the convention `tablename_id`, you can specify a
//! custom one to `#[belongs_to]` by adding a `foreign_key` argument to the
//! attribute like so `#[belongs_to(Foo, foreign_key="mykey")]`.
//!
//! Once the associations are defined, you can join between the two tables using the
//! [`inner_join`][inner-join] or [`left_outer_join`][left-outer-join].
//!
//! [inner-join]: /diesel/query_source/trait.Table.html#method.inner_join
//! [left-outer-join]: /diesel/query_source/trait.Table.html#method.left_outer_join
//!
//! ```ignore
//! let data: Vec<(User, Post)> = users::table.inner_join(posts::table).load(&connection);
//! ```
//!
//! Note: Due to language limitations, only two tables can be joined per query. This will change in
//! the future.
//!
//! Typically however, queries are loaded in multiple queries. For most datasets, the reduced
//! amount of duplicated information sent over the wire saves more time than the extra round trip
//! costs us. You can load the children for a single parent using the
//! [`belonging_to`][belonging-to]
//!
//! [belonging-to]: /diesel/prelude/trait.BelongingToDsl.html#tymethod.belonging_to
//!
//! ```ignore
//! let user = try!(users::find(1).first(&connection));
//! let posts = Post::belonging_to(&user).load(&connection);
//! ```
//!
//! If you're coming from other ORMs, you'll notice that this design is quite different from most.
//! There you would have an instance method on the parent, or have the children stored somewhere on
//! the posts. This design leads to many problems, including [N+1 query
//! bugs][load-your-entire-database-into-memory-lol], and runtime errors when accessing an
//! association that isn't there.
//!
//! [load-your-entire-database-into-memory-lol]: http://stackoverflow.com/q/97197/1254484
//!
//! In Diesel, data and its associations are considered to be separate. If you want to pass around
//! a user and all of its posts, that type is `(User, Vec<Post>)`.
//!
//! Next lets look at how to load the children for more than one parent record.
//! [`belonging_to`][belonging-to] can be used to load the data, but we'll also need to group it
//! with its parents. For this we use an additional method [`grouped_by`][grouped-by]
//!
//! [grouped-by]: trait.GroupedBy.html#tymethod.grouped_by
//!
//! ```ignore
//! fn first_twenty_users_and_their_posts(conn: &PgConnection) -> QueryResult<Vec<(User, Vec<Post>)>> {
//!     let users = try!(users::limit(20).load::<User>(conn));
//!     let posts = try!(Post::belonging_to(&users).load::<Post>(conn));
//!     let grouped_posts = posts.grouped_by(&users);
//!     users.into_iter().zip(grouped_posts).collect()
//! }
//! ```
//!
//! [`grouped_by`][grouped-by] takes a `Vec<Child>` and a `Vec<Parent>` and returns a
//! `Vec<Vec<Child>>` where the index of the children matches the index of the parent they belong
//! to. Or to put it another way, it returns them in an order ready to be `zip`ed with the parents. You
//! can do this multiple times. For example, if you wanted to load the comments for all the posts
//! as well, you could do this: (explicit type annotations have been added for documentation
//! purposes)
//!
//! ```ignore
//! let posts: Vec<Post> = try!(Post::belonging_to(&users).load());
//! let comments: Vec<Comment> = try!(Comment::belonging_to(&posts).load());
//! let comments: Vec<Vec<Comment>> = comments.grouped_by(&posts);
//! let posts_and_comments: Vec<Vec<(Post, Vec<Comment>)>> = posts.into_iter().zip(comments).grouped_by(&users);
//! let result: Vec<(User, Vec<(Post, Vec<Comment>)>)> = users.into_iter().zip(posts_and_comments).collect();
//! ```
//!
//! And that's it. This module will be expanded in the future with more complex joins, and the
//! ability to define "through" associations (e.g. load all the comments left on any posts written
//! by a user in a single query). However, the goal is to provide simple building blocks which can
//! be used to construct the complex behavior applications need.
mod belongs_to;

use std::hash::Hash;

use query_source::Table;

pub use self::belongs_to::{BelongsTo, GroupedBy};

pub trait HasTable {
    type Table: Table;

    fn table() -> Self::Table;
}

impl<'a, T: HasTable> HasTable for &'a T {
    type Table = T::Table;

    fn table() -> Self::Table {
        T::table()
    }
}

/// Represents a struct which can be identified on a single table in the
/// database. This must be implemented to use associations, and some features of
/// updating. This trait is usually implemented on a reference to a struct, not
/// the struct itself.
///
/// ### Deriving
///
/// This trait can be automatically derived using `diesel_codegen` by adding
/// `#[derive(Identifiable)]` to your struct. The primary key will be assumed to be a field and
/// column called `id`. If it's not, you can annotate your structure with `#[primary_key(your_id)]`
/// or `#[primary_key(your_id, second_id)]`. By default the table will be assumed to be the plural
/// form of the struct name (using *very* dumb pluralization -- it just adds an `s` at the end). If
/// your table name differs from that convention, or requires complex pluralization, it can be
/// specified using `#[table_name = "some_table_name"]`. The inferred table name is considered
/// public API and will never change without a major version bump.
pub trait Identifiable: HasTable {
    type Id: Hash + Eq;

    fn id(self) -> Self::Id;
}
<|endoftext|>


<commit_before>#![allow(unused_variables, unused_mut, dead_code)]

extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    for i in 0..361 {
        println!("1");
        canvas.apply(Command::Move {
            distance: 10.,
        });
        println!("2");
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
        println!("3");
        //canvas.apply(Command::Pen {
        //    enabled: i % 2 == 0,
        //});
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Mul};

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    trait LinearInterpolation {
        /// Interpolate between self and the given target
        ///
        /// t must be between 0.0 and 1.0
        fn interpolate(self, target: Self, t: f64) -> Self;
    }

    impl LinearInterpolation for f64 {
        fn interpolate(self, target: Self, t: f64) -> Self {
            (target - self) * t
        }
    }

    impl LinearInterpolation for (f64, f64) {
        fn interpolate(self, target: Self, t: f64) -> Self {
            let (x1, y1) = self;
            let (x2, y2) = target;

            let x = x1.interpolate(x2, t);
            let y = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
            (x, y)
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: (f64, f64),
        end: (f64, f64),
        pen: Pen,
    }

    impl Path {
        /// Returns the size of the line represented by this path
        fn len(&self) -> f64 {
            let (x1, y1) = self.start;
            let (x2, y2) = self.end;
            ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt()
        }

        /// Linearly interpolate between the points in this path
        fn interpolate(&self, t: f64) -> (f64, f64) {
            self.start.interpolate(self.end, t)
        }
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: (f64, f64),
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Default::default(),
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            match command {
                                Command::Move {distance} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    if distance != 0. {
                                        let current_x = turtle.position.0;
                                        let current_y = turtle.position.1;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        println!("move forward {:?}", (x, y));
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start: (current_x, current_y),
                                                    end: (current_x + x, current_y + y),
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => unimplemented!(),
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = (width * 0.5, height * 0.5);

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis();
                            println!("elapsed = {}", elapsed);

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    let speed = speed.to_absolute();
                                    let length = path.len();
                                    println!("{:?}", (speed, length));
                                    let total_time = length / speed * 1000.; // ms
                                    println!("total_time = {}", total_time);

                                    let progress = elapsed as f64 / total_time;
                                    if progress > 1.0 {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                    }
                                    else {
                                        println!("progress = {}", progress);
                                        let current = path.interpolate(progress);
                                        turtle.position = current;
                                        println!("turtle.position = {:?}", turtle.position);

                                        let Pen {thickness, color, enabled} = path.pen;
                                        let start = path.start;

                                        if enabled {
                                            line(color.into(), thickness,
                                            [
                                            center.0 + start.0, center.1 + start.1,
                                            center.0 + current.0, center.1 + current.1
                                            ],
                                            c.transform, g);
                                        }
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = speed.to_rotation();
                                    animation_complete = true;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            line(pen.color.into(), pen.thickness,
                                [start.0, start.1, end.0, end.1],
                                c.transform, g);
                        }

                        // TODO: Draw the turtle
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<commit_msg>Large refactorings to allow for the use of graphics::math and do smarter vector calculations. Actually made some progress<commit_after>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    for _ in 0..361 {
        canvas.apply(Command::Move {
            distance: 10.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
        //canvas.apply(Command::Pen {
        //    enabled: i % 2 == 0,
        //});
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Mul};

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Default::default(),
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            match command {
                                Command::Move {distance} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    if distance != 0. {
                                        let start = turtle.position;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start: start,
                                                    end: math::add(start, [x, y]),
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => unimplemented!(),
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, path_length);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = speed.to_rotation();
                                    animation_complete = true;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // TODO: Draw the turtle
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]
extern crate ferrous_threads;
use ferrous_threads::TaskPool;
use std::process::Command;
use std::string::String;
use std::io::Write;
use std::io;

fn main() {
    let pool = TaskPool::new(4);
    let n: usize = 10000;
    let mut vec = Vec::new();

    pool.enqueue(move || { sleep_and_cat() }).ok().expect("closure not queued");
    pool.enqueue(move || {
        for i in (0..n) {
            vec.push(i);
            vec[i/2] = i;
        }
    }).ok().expect("closure not queued");
    pool.enqueue(move || { stdin_and_echo() }).ok().expect("closure not queued");
}

fn sleep_and_cat() {
    let mut stdout = io::stdout();
    std::thread::sleep_ms(5000);

    let output = Command::new("cat")
        .arg("README.md")
        .output()
        .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });
    assert!(stdout.write_all(String::from_utf8(output.stdout).ok().unwrap().as_bytes()).is_ok());
    assert!(stdout.write_all(String::from_utf8(output.stderr).ok().unwrap().as_bytes()).is_ok());
}

fn stdin_and_echo() {
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();

    let mut buf = String::new();
    let echo = String::from_str("You said: ");
    let magic = String::from_str("Rhino\n");
    assert!(stdout.write_all(magic.as_bytes()).is_ok());

    while buf != magic {
        buf.clear();
        assert!(stdin.read_line(&mut buf).is_ok());
        assert!(stdout.write_all(echo.as_bytes()).is_ok());
        assert!(stdout.write_all(buf.as_bytes()).is_ok());
    }

    assert!(stdout.write_all(String::from_str("Goodbye!\n").as_bytes()).is_ok());
}
<commit_msg>rust deprecation warnings on String::from_str<commit_after>#![feature(collections)]
extern crate ferrous_threads;
use ferrous_threads::TaskPool;
use std::process::Command;
use std::string::String;
use std::io::Write;
use std::io;

fn main() {
    let pool = TaskPool::new(4);
    let n: usize = 10000;
    let mut vec = Vec::new();

    pool.enqueue(move || { sleep_and_cat() }).ok().expect("closure not queued");
    pool.enqueue(move || {
        for i in (0..n) {
            vec.push(i);
            vec[i/2] = i;
        }
    }).ok().expect("closure not queued");
    pool.enqueue(move || { stdin_and_echo() }).ok().expect("closure not queued");
}

fn sleep_and_cat() {
    let mut stdout = io::stdout();
    std::thread::sleep_ms(5000);

    let output = Command::new("cat")
        .arg("README.md")
        .output()
        .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });
    assert!(stdout.write_all(String::from_utf8(output.stdout).ok().unwrap().as_bytes()).is_ok());
    assert!(stdout.write_all(String::from_utf8(output.stderr).ok().unwrap().as_bytes()).is_ok());
}

fn stdin_and_echo() {
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();

    let mut buf = String::new();
    let echo = String::from("You said: ");
    let magic = String::from("Rhino\n");
    assert!(stdout.write_all(magic.as_bytes()).is_ok());

    while buf != magic {
        buf.clear();
        assert!(stdin.read_line(&mut buf).is_ok());
        assert!(stdout.write_all(echo.as_bytes()).is_ok());
        assert!(stdout.write_all(buf.as_bytes()).is_ok());
    }

    assert!(stdout.write_all(String::from("Goodbye!\n").as_bytes()).is_ok());
}
<|endoftext|>


<commit_before>use std::cast;
use std::mem::size_of;
use std::raw::Slice;
use std::num::Zero;
use std::rc::Rc;
use sync::Mutex;

mod buffer;
mod schema;

static LEAF_MARKER: u8 = 0b11111111;
static BRANCH_MARKER: u8 = 0b0;

/* simple type alias to simplify signatures */
type ConcurrentManager = Rc<Mutex<buffer::BufferManager>>;

struct BTree<'a, K> {
	segment: u64,
	manager: ConcurrentManager,
	tree: LazyNode,
	next_free_page: u64,
}

impl<'a, K: TotalOrd + Zero + Clone> BTree<'a, K> {
	fn new<'b>(segment_id: u64, manager: ConcurrentManager) -> BTree<'b, K> {
		let tree_base = buffer::join_segment(segment_id, 1);
		// TODO read tree and next free page from page 0
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(tree_base),
			next_free_page: 2,
		}
	}

	fn insert(&mut self, key: K, value: schema::TID) {
		// it is not allowed for the key to be the Zero value, that is used
		// as marker for invalid data
		assert!(!key.is_zero());
		let node = self.tree.load(self.manager.clone());
		// try insertion and see if the root was split
		let candidate = match node {
			Branch(mut n) => n.insert_value(self, key, value),
			Leaf(mut n) => n.insert_value(key, value),
		};
		// set new tree root if it was split
		match candidate {
			Some(new_node) => self.tree = new_node,
			None => (),
		}
	}

	fn next_page(&mut self) -> u64 {
		let n = self.next_free_page;
		self.next_free_page += 1;
		n
	}

	fn create_branch_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let mut manager = self.manager.lock();
		let pagelock = manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		data[0] = BRANCH_MARKER;
		LazyNode::new(page_path)
	}

	fn create_leaf_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let mut manager = self.manager.lock();
		let pagelock = manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		// marker to be a leaf page
		data[0] = LEAF_MARKER;
		LazyNode::new(page_path)

	}

	fn erase(&mut self, key: K) {
	}

	fn lookup(&self, key: &K) -> Option<schema::TID> {
		let node = self.tree.load(self.manager.clone());
		match node {
			Branch(n) => n.lookup(self.manager.clone(), key),
			Leaf(n) => n.lookup(key),
		}
	}
}

/* a placeholder for the actual page */
struct LazyNode {
	page_id: u64,
}

impl LazyNode {
	fn new(page_id: u64) -> LazyNode {
		LazyNode {page_id: page_id}
	}

	/*
	 * As this is just a placeholder, return the actual node that his is
	 * representing
	 */
	fn load<'a, K: TotalOrd + Zero + Clone>(&self, manager: ConcurrentManager) -> Node<'a, K> {
		let pagelock = {
			let mut managerlock = manager.lock();
			managerlock.fix_page(self.page_id).unwrap()
		};

		let mut is_leaf = false;
		{
			let page = pagelock.read();
			let page_data = page.get_data();
			if page_data[0] == LEAF_MARKER {
				is_leaf = true;
			} else if page_data[0] == BRANCH_MARKER {
				is_leaf = false;
			} else {
				fail!("Invalid page type");
			}
		}
		if is_leaf {
			Leaf(LeafNode::new(manager, pagelock))
		} else {
			Branch(BranchNode::new(manager, pagelock))
		}
	}

}

/* a node might either be an inner node (branch node) or a leaf node (LeafNode) */
enum Node<'a, K> {
	Branch(BranchNode<'a, K>),
	Leaf(LeafNode<'a, K>),
}

/* leaf pages consist mainly of leaf entries which are (K, TID) pairs */
struct LeafEntry<K> {
	key: K,
	tid: schema::TID,
}

/* branch pages consist mainly of branch entries which are (K, page_id) pairs */
struct BranchEntry<K> {
	key: K,
	page_id: u64,
}

struct LeafNode<'a, K> {
	capacity: uint,
	entries: &'a mut [LeafEntry<K>],
	manager: ConcurrentManager,
	frame: buffer::ConcurrentFrame,
}

impl<'a, K: TotalOrd + Zero + Clone> LeafNode<'a, K> {
	fn new(manager: ConcurrentManager, frame: buffer::ConcurrentFrame) -> LeafNode<'a, K> {
		let mut r = {
			let framelock = frame.read();
			let page = framelock.get_data();
			// first byte is a Leaf/Branch marker
			let entry_size = size_of::<LeafEntry<K>>();
			let entry_num = (page.len() - size_of::<u8>()) / entry_size;
			let start_from = entry_size;

			let mut entries: &mut[LeafEntry<K>] = unsafe {
				cast::transmute(
					Slice::<LeafEntry<K>> {
						data: page.slice_from(start_from).as_ptr() as *() as *LeafEntry<K>,
						len: entry_num,
					}
				)
			};
			entries
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			//println!("Entry {:?}", r[i]);
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

		println!("Instantiating leaf node with capacity {}", capacity);
		LeafNode {
			entries: r,
			capacity: capacity,
			manager: manager,
			frame: frame,
		}
	}

	fn insert_value(&mut self, key: K, tid: schema::TID) -> Option<LazyNode> {
		println!("Leaf insertion, remaining capacity {}", self.capacity);
		if self.capacity == 0 {
			// TODO split
			fail!("Not implemented");
		}

		// find place to insert
		let location = self.find_slot(&key);
		println!("Location found: {}", location);
		// free that spot
		self.shift_from(location);
		// and put it in
		self.entries[location].key = key;
		self.entries[location].tid = tid;
		self.capacity -= 1;

		// insertion went fine, done
		None
	}

	/* finds the location at which a key should be inserted */
	fn find_slot(&self, key: &K) -> uint {
		let mut found = 0;
		for i in range(0, self.entries.len()) {
			//println!("Entry {:?}", self.entries[i]);
			if &self.entries[i].key > key {

				found = i - 1;
				break;
			}
		}
		found
	}

	/* moves all items from `index` one number back */
	fn shift_from(&mut self, index: uint) {
		// actually, this rotates right by 1 starting from index
		let last_elem = self.entries.len() - 1;
		for i in range(index, last_elem) {
			self.entries.swap(i, last_elem);
		}
	}

	fn lookup(self, key: &K) -> Option<schema::TID> {
		for i in range(0, self.entries.len()) {
			if &self.entries[i].key == key {
				return Some(self.entries[i].tid)
			}
		}
		None
	}
}

#[unsafe_destructor]
impl<'a, K> Drop for LeafNode<'a, K> {
	fn drop(&mut self) {
		let mut manager = self.manager.lock();
		//println!("Writing back leaf page {:?}", self.frame);
		// TODO: figure out if page was modified since loading
		manager.unfix_page(self.frame.clone(), true);
	}
}

struct BranchNode<'a, K> {
	capacity: uint,
	entries: &'a mut [BranchEntry<K>],
	manager: ConcurrentManager,
	frame: buffer::ConcurrentFrame,
}

impl<'a, K: TotalOrd + Zero + Clone> BranchNode<'a, K> {
	fn new(manager: ConcurrentManager, frame: buffer::ConcurrentFrame) -> BranchNode<'a, K> {
		let mut r = {
			let framelock = frame.read();
			let page = framelock.get_data();

			let entry_size = size_of::<BranchEntry<K>>();
			let entry_num = (page.len() - size_of::<u8>()) / entry_size;
			let start_from = entry_size;
			let mut r: &mut [BranchEntry<K>] = unsafe {
				cast::transmute(
					Slice::<BranchEntry<K>> {
						data: page.slice_from(start_from).as_ptr() as *() as *BranchEntry<K>,
						len: entry_num,
					}
				)
			};
			r
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if r[i].page_id != 0 {
				capacity -= 1;
			}
		}

		println!("BranchNode computed capacity: {}", capacity);

		BranchNode {
			entries: r,
			capacity: capacity,
			manager: manager,
			frame: frame,
		}
	}

	/* might return a new branch node if this one was split */
	fn insert_value(&mut self, tree: &mut BTree<K>, key: K, value: schema::TID) -> Option<LazyNode> {
		// locate the place where to insert
		let mut place = 0;
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			if key <= self.entries[i].key {
				place = i;
				break;
			}
		}
		println!("Found place to insert, {}, containing {:?}", place, self.entries[place]);

		let go_to_page = self.entries[place].page_id;
		println!("go_to_page {}", go_to_page);
		if go_to_page == 0 {
			// there is no such page, but it should be created
			let lazy_node = tree.create_leaf_page();
			let new_node = lazy_node.load(tree.manager.clone());
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key.clone(), value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			self.entries[place].key = key;
			return split_candidate
		} else {
			let lazy_node = LazyNode::new(go_to_page);
			let new_node = lazy_node.load(tree.manager.clone());
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key, value),
				Branch(mut n) => n.insert_value(tree, key, value),
			};
			return split_candidate
		}
	}

	fn lookup(self, manager: ConcurrentManager, key: &K) -> Option<schema::TID> {
		// find the page to descend to
		let mut next_page = None;
		for i in range(0, self.entries.len()) {
			// skip all empty fields
			if self.entries[i].key.is_zero() && self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry {}: {:?}", i, self.entries[i]);
			if &self.entries[i].key <= key {
				// found the branch into which to descend
				next_page = Some(self.entries[i].page_id);
				break;
			}
		}

		match next_page {
			// if there is no page to descend to, it can't be found
			None => None,
			Some(page_id) => {
				let ln = LazyNode::new(page_id);
				let node = ln.load(manager);
				match node {
					Branch(n) => n.lookup(self.manager.clone(), key),
					Leaf(n) => n.lookup(key),
				}
			}
		}
	}
}

#[unsafe_destructor]
impl<'a, K> Drop for BranchNode<'a, K> {
	fn drop(&mut self) {
		let mut manager = self.manager.lock();
		//println!("Ohai, unfixing page");
		// TODO: figure out if page was modified since loading
		manager.unfix_page(self.frame.clone(), true);
	}
}

#[test]
fn simple_insert() {
	let p = Path::new(".");
	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, Rc::new(Mutex::new(manager)));
	let some_tid = schema::TID::new(0, 0);
	bt.insert(42, some_tid);
	let res = bt.lookup(&42).unwrap();
	assert_eq!(some_tid, res);
}

#[test]
fn split_insert() {
	let p = Path::new(".");
	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, Rc::new(Mutex::new(manager)));
	let some_tid = schema::TID::new(23, 42);
	for i in range(1, 3) {
		bt.insert(i, some_tid);
		let res = bt.lookup(&i).unwrap();
		assert_eq!(some_tid, res);
	}
	assert!(false);
}

#[test]
fn lookup_nonexisting() {
	let p = Path::new(".");
	let manager = buffer::BufferManager::new(1024, p.clone());
	let bt = BTree::new(23, Rc::new(Mutex::new(manager)));
	let result = bt.lookup(&42);
	assert_eq!(result, None);
}

#[test]
fn create_leaf_page() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let pagelock = manager.fix_page(10).unwrap();
	let page = pagelock.read();
	//let lp: LeafNode<u64> = LeafNode::new(page.get_data(), Rc::new(Mutex::new(manager)), pagelock);
	//println!("lp len: {}", lp.entries.len());
	assert!(false);
}
<commit_msg>Cleaned up trait dependencies<commit_after>use std::cast;
use std::mem::size_of;
use std::raw::Slice;
use std::num::Zero;
use std::rc::Rc;
use sync::Mutex;

mod buffer;
mod schema;

static LEAF_MARKER: u8 = 0b11111111;
static BRANCH_MARKER: u8 = 0b0;

/* simple type alias to simplify signatures */
type ConcurrentManager = Rc<Mutex<buffer::BufferManager>>;

/* a new trait which specifies which traits our keys should implement */
trait Keyish: TotalOrd + Zero + Clone {}
impl<T: TotalOrd + Zero + Clone> Keyish for T {}

struct BTree<'a, K> {
	segment: u64,
	manager: ConcurrentManager,
	tree: LazyNode,
	next_free_page: u64,
}

impl<'a, K: Keyish> BTree<'a, K> {
	fn new<'b>(segment_id: u64, manager: ConcurrentManager) -> BTree<'b, K> {
		let tree_base = buffer::join_segment(segment_id, 1);
		// TODO read tree and next free page from page 0
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(tree_base),
			next_free_page: 2,
		}
	}

	fn insert(&mut self, key: K, value: schema::TID) {
		// it is not allowed for the key to be the Zero value, that is used
		// as marker for invalid data
		assert!(!key.is_zero());
		let node = self.tree.load(self.manager.clone());
		// try insertion and see if the root was split
		let candidate = match node {
			Branch(mut n) => n.insert_value(self, key, value),
			Leaf(mut n) => n.insert_value(key, value),
		};
		// set new tree root if it was split
		match candidate {
			Some(new_node) => self.tree = new_node,
			None => (),
		}
	}

	fn next_page(&mut self) -> u64 {
		let n = self.next_free_page;
		self.next_free_page += 1;
		n
	}

	fn create_branch_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let mut manager = self.manager.lock();
		let pagelock = manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		data[0] = BRANCH_MARKER;
		LazyNode::new(page_path)
	}

	fn create_leaf_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let mut manager = self.manager.lock();
		let pagelock = manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		// marker to be a leaf page
		data[0] = LEAF_MARKER;
		LazyNode::new(page_path)

	}

	fn erase(&mut self, key: K) {
	}

	fn lookup(&self, key: &K) -> Option<schema::TID> {
		let node = self.tree.load(self.manager.clone());
		match node {
			Branch(n) => n.lookup(self.manager.clone(), key),
			Leaf(n) => n.lookup(key),
		}
	}
}

/* a placeholder for the actual page */
struct LazyNode {
	page_id: u64,
}

impl LazyNode {
	fn new(page_id: u64) -> LazyNode {
		LazyNode {page_id: page_id}
	}

	/*
	 * As this is just a placeholder, return the actual node that his is
	 * representing
	 */
	fn load<'a, K: Keyish>(&self, manager: ConcurrentManager) -> Node<'a, K> {
		let pagelock = {
			let mut managerlock = manager.lock();
			managerlock.fix_page(self.page_id).unwrap()
		};

		let mut is_leaf = false;
		{
			let page = pagelock.read();
			let page_data = page.get_data();
			if page_data[0] == LEAF_MARKER {
				is_leaf = true;
			} else if page_data[0] == BRANCH_MARKER {
				is_leaf = false;
			} else {
				fail!("Invalid page type");
			}
		}
		if is_leaf {
			Leaf(LeafNode::new(manager, pagelock))
		} else {
			Branch(BranchNode::new(manager, pagelock))
		}
	}

}

/* a node might either be an inner node (branch node) or a leaf node (LeafNode) */
enum Node<'a, K> {
	Branch(BranchNode<'a, K>),
	Leaf(LeafNode<'a, K>),
}

/* leaf pages consist mainly of leaf entries which are (K, TID) pairs */
struct LeafEntry<K> {
	key: K,
	tid: schema::TID,
}

/* branch pages consist mainly of branch entries which are (K, page_id) pairs */
struct BranchEntry<K> {
	key: K,
	page_id: u64,
}

struct LeafNode<'a, K> {
	capacity: uint,
	entries: &'a mut [LeafEntry<K>],
	manager: ConcurrentManager,
	frame: buffer::ConcurrentFrame,
}

impl<'a, K: Keyish> LeafNode<'a, K> {
	fn new(manager: ConcurrentManager, frame: buffer::ConcurrentFrame) -> LeafNode<'a, K> {
		let mut r = {
			let framelock = frame.read();
			let page = framelock.get_data();
			// first byte is a Leaf/Branch marker
			let entry_size = size_of::<LeafEntry<K>>();
			let entry_num = (page.len() - size_of::<u8>()) / entry_size;
			let start_from = entry_size;

			let mut entries: &mut[LeafEntry<K>] = unsafe {
				cast::transmute(
					Slice::<LeafEntry<K>> {
						data: page.slice_from(start_from).as_ptr() as *() as *LeafEntry<K>,
						len: entry_num,
					}
				)
			};
			entries
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			//println!("Entry {:?}", r[i]);
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

		println!("Instantiating leaf node with capacity {}", capacity);
		LeafNode {
			entries: r,
			capacity: capacity,
			manager: manager,
			frame: frame,
		}
	}

	fn insert_value(&mut self, key: K, tid: schema::TID) -> Option<LazyNode> {
		println!("Leaf insertion, remaining capacity {}", self.capacity);
		if self.capacity == 0 {
			// TODO split
			fail!("Not implemented");
		}

		// find place to insert
		let location = self.find_slot(&key);
		println!("Location found: {}", location);
		// free that spot
		self.shift_from(location);
		// and put it in
		self.entries[location].key = key;
		self.entries[location].tid = tid;
		self.capacity -= 1;

		// insertion went fine, done
		None
	}

	/* finds the location at which a key should be inserted */
	fn find_slot(&self, key: &K) -> uint {
		let mut found = 0;
		for i in range(0, self.entries.len()) {
			//println!("Entry {:?}", self.entries[i]);
			if &self.entries[i].key > key {

				found = i - 1;
				break;
			}
		}
		found
	}

	/* moves all items from `index` one number back */
	fn shift_from(&mut self, index: uint) {
		// actually, this rotates right by 1 starting from index
		let last_elem = self.entries.len() - 1;
		for i in range(index, last_elem) {
			self.entries.swap(i, last_elem);
		}
	}

	fn lookup(self, key: &K) -> Option<schema::TID> {
		for i in range(0, self.entries.len()) {
			if &self.entries[i].key == key {
				return Some(self.entries[i].tid)
			}
		}
		None
	}
}

#[unsafe_destructor]
impl<'a, K> Drop for LeafNode<'a, K> {
	fn drop(&mut self) {
		let mut manager = self.manager.lock();
		//println!("Writing back leaf page {:?}", self.frame);
		// TODO: figure out if page was modified since loading
		manager.unfix_page(self.frame.clone(), true);
	}
}

struct BranchNode<'a, K> {
	capacity: uint,
	entries: &'a mut [BranchEntry<K>],
	manager: ConcurrentManager,
	frame: buffer::ConcurrentFrame,
}

impl<'a, K: Keyish> BranchNode<'a, K> {
	fn new(manager: ConcurrentManager, frame: buffer::ConcurrentFrame) -> BranchNode<'a, K> {
		let mut r = {
			let framelock = frame.read();
			let page = framelock.get_data();

			let entry_size = size_of::<BranchEntry<K>>();
			let entry_num = (page.len() - size_of::<u8>()) / entry_size;
			let start_from = entry_size;
			let mut r: &mut [BranchEntry<K>] = unsafe {
				cast::transmute(
					Slice::<BranchEntry<K>> {
						data: page.slice_from(start_from).as_ptr() as *() as *BranchEntry<K>,
						len: entry_num,
					}
				)
			};
			r
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if r[i].page_id != 0 {
				capacity -= 1;
			}
		}

		println!("BranchNode computed capacity: {}", capacity);

		BranchNode {
			entries: r,
			capacity: capacity,
			manager: manager,
			frame: frame,
		}
	}

	/* might return a new branch node if this one was split */
	fn insert_value(&mut self, tree: &mut BTree<K>, key: K, value: schema::TID) -> Option<LazyNode> {
		// locate the place where to insert
		let mut place = 0;
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			if key <= self.entries[i].key {
				place = i;
				break;
			}
		}
		println!("Found place to insert, {}, containing {:?}", place, self.entries[place]);

		let go_to_page = self.entries[place].page_id;
		println!("go_to_page {}", go_to_page);
		if go_to_page == 0 {
			// there is no such page, but it should be created
			let lazy_node = tree.create_leaf_page();
			let new_node = lazy_node.load(tree.manager.clone());
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key.clone(), value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			self.entries[place].key = key;
			return split_candidate
		} else {
			let lazy_node = LazyNode::new(go_to_page);
			let new_node = lazy_node.load(tree.manager.clone());
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key, value),
				Branch(mut n) => n.insert_value(tree, key, value),
			};
			return split_candidate
		}
	}

	fn lookup(self, manager: ConcurrentManager, key: &K) -> Option<schema::TID> {
		// find the page to descend to
		let mut next_page = None;
		for i in range(0, self.entries.len()) {
			// skip all empty fields
			if self.entries[i].key.is_zero() && self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry {}: {:?}", i, self.entries[i]);
			if &self.entries[i].key <= key {
				// found the branch into which to descend
				next_page = Some(self.entries[i].page_id);
				break;
			}
		}

		match next_page {
			// if there is no page to descend to, it can't be found
			None => None,
			Some(page_id) => {
				let ln = LazyNode::new(page_id);
				let node = ln.load(manager);
				match node {
					Branch(n) => n.lookup(self.manager.clone(), key),
					Leaf(n) => n.lookup(key),
				}
			}
		}
	}
}

#[unsafe_destructor]
impl<'a, K> Drop for BranchNode<'a, K> {
	fn drop(&mut self) {
		let mut manager = self.manager.lock();
		//println!("Ohai, unfixing page");
		// TODO: figure out if page was modified since loading
		manager.unfix_page(self.frame.clone(), true);
	}
}

#[test]
fn simple_insert() {
	let p = Path::new(".");
	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, Rc::new(Mutex::new(manager)));
	let some_tid = schema::TID::new(0, 0);
	bt.insert(42, some_tid);
	let res = bt.lookup(&42).unwrap();
	assert_eq!(some_tid, res);
}

#[test]
fn split_insert() {
	let p = Path::new(".");
	let manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, Rc::new(Mutex::new(manager)));
	let some_tid = schema::TID::new(23, 42);
	for i in range(1, 3) {
		bt.insert(i, some_tid);
		let res = bt.lookup(&i).unwrap();
		assert_eq!(some_tid, res);
	}
	assert!(false);
}

#[test]
fn lookup_nonexisting() {
	let p = Path::new(".");
	let manager = buffer::BufferManager::new(1024, p.clone());
	let bt = BTree::new(23, Rc::new(Mutex::new(manager)));
	let result = bt.lookup(&42);
	assert_eq!(result, None);
}

#[test]
fn create_leaf_page() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let pagelock = manager.fix_page(10).unwrap();
	let page = pagelock.read();
	//let lp: LeafNode<u64> = LeafNode::new(page.get_data(), Rc::new(Mutex::new(manager)), pagelock);
	//println!("lp len: {}", lp.entries.len());
	assert!(false);
}
<|endoftext|>


<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi as glib_ffi;
use gobject_ffi;
use std::borrow::Borrow;
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::slice;
use std::ptr;
use std::mem;
use translate::*;

glib_wrapper! {
    /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`).
    ///
    /// `From` implementations that take references (e.g. `&[u8]`) copy the
    /// data. The `from_static` constructor avoids copying static data.
    ///
    /// ```
    /// use glib::Bytes;
    ///
    /// let v = vec![1, 2, 3];
    /// let b = Bytes::from(&v);
    /// assert_eq!(v, b);
    ///
    /// let s = b"xyz";
    /// let b = Bytes::from_static(s);
    /// assert_eq!(&s[..], b);
    /// ```
    pub struct Bytes(Shared<glib_ffi::GBytes>);

    match fn {
        ref => |ptr| glib_ffi::g_bytes_ref(ptr),
        unref => |ptr| glib_ffi::g_bytes_unref(ptr),
        get_type => || glib_ffi::g_bytes_get_type(),
    }
}

impl Bytes {
    /// Copies `data` into a new shared slice.
    fn new(data: &[u8]) -> Bytes {
        unsafe { from_glib_full(glib_ffi::g_bytes_new(data.as_ptr() as *const _, data.len())) }
    }

    /// Creates a view into static `data` without copying.
    pub fn from_static(data: &'static [u8]) -> Bytes {
        unsafe {
            from_glib_full(glib_ffi::g_bytes_new_static(data.as_ptr() as *const _, data.len()))
        }
    }
}

unsafe impl Send for Bytes { }
unsafe impl Sync for Bytes { }

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes {
    fn from(value: &'a T) -> Bytes {
        Bytes::new(value.borrow())
    }
}

impl fmt::Debug for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Bytes")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

impl Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut len = 0;
            let ptr = glib_ffi::g_bytes_get_data(self.to_glib_none().0, &mut len);
            debug_assert!(!ptr.is_null() || len == 0);
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

impl PartialEq for Bytes {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_bytes_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Bytes { }

impl PartialOrd for Bytes {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.partial_cmp(&0)
        }
    }
}

impl Ord for Bytes {
    fn cmp(&self, other: &Self) -> Ordering {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.cmp(&0)
        }
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    }
}

impl_cmp!(Bytes, [u8]);
impl_cmp!(Bytes, &'a [u8]);
impl_cmp!(&'a Bytes, [u8]);
impl_cmp!(Bytes, Vec<u8>);
impl_cmp!(&'a Bytes, Vec<u8>);

impl Hash for Bytes {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(self, state)
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashSet;
    use super::*;

    #[test]
    fn eq() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a1 = Bytes::from(abc);
        let a2 = Bytes::from(abc);
        let d = Bytes::from(def);
        assert_eq!(a1, a2);
        assert_eq!(def, d);
        assert!(a1 != d);
        assert!(a1 != def);
    }

    #[test]
    fn ord() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a = Bytes::from(abc);
        let d = Bytes::from(def);
        assert!(a < d);
        assert!(a < def);
        assert!(abc < d);
        assert!(d > a);
        assert!(d > abc);
        assert!(def > a);
    }

    #[test]
    fn hash() {
        let b1 = Bytes::from(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        let b3 = Bytes::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }

    #[test]
    fn from_static() {
        let b1 = Bytes::from_static(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        assert_eq!(b1, b2);
    }
}
<commit_msg>Allow creating Bytes from any AsRef<[u8]> by copying<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi as glib_ffi;
use gobject_ffi;
use std::borrow::Borrow;
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::slice;
use std::ptr;
use std::mem;
use translate::*;

glib_wrapper! {
    /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`).
    ///
    /// `From` implementations that take references (e.g. `&[u8]`) copy the
    /// data. The `from_static` constructor avoids copying static data.
    ///
    /// ```
    /// use glib::Bytes;
    ///
    /// let v = vec![1, 2, 3];
    /// let b = Bytes::from(&v);
    /// assert_eq!(v, b);
    ///
    /// let s = b"xyz";
    /// let b = Bytes::from_static(s);
    /// assert_eq!(&s[..], b);
    /// ```
    pub struct Bytes(Shared<glib_ffi::GBytes>);

    match fn {
        ref => |ptr| glib_ffi::g_bytes_ref(ptr),
        unref => |ptr| glib_ffi::g_bytes_unref(ptr),
        get_type => || glib_ffi::g_bytes_get_type(),
    }
}

impl Bytes {
    /// Copies `data` into a new shared slice.
    fn new<T: AsRef<[u8]>>(data: T) -> Bytes {
        let data = data.as_ref();
        unsafe { from_glib_full(glib_ffi::g_bytes_new(data.as_ptr() as *const _, data.len())) }
    }

    /// Creates a view into static `data` without copying.
    pub fn from_static(data: &'static [u8]) -> Bytes {
        unsafe {
            from_glib_full(glib_ffi::g_bytes_new_static(data.as_ptr() as *const _, data.len()))
        }
    }
}

unsafe impl Send for Bytes { }
unsafe impl Sync for Bytes { }

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes {
    fn from(value: &'a T) -> Bytes {
        Bytes::new(value.borrow())
    }
}

impl fmt::Debug for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Bytes")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

impl Deref for Bytes {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut len = 0;
            let ptr = glib_ffi::g_bytes_get_data(self.to_glib_none().0, &mut len);
            debug_assert!(!ptr.is_null() || len == 0);
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

impl PartialEq for Bytes {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_bytes_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Bytes { }

impl PartialOrd for Bytes {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.partial_cmp(&0)
        }
    }
}

impl Ord for Bytes {
    fn cmp(&self, other: &Self) -> Ordering {
        unsafe {
            let ret = glib_ffi::g_bytes_compare(self.to_glib_none().0 as *const _,
                other.to_glib_none().0 as *const _);
            ret.cmp(&0)
        }
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    }
}

impl_cmp!(Bytes, [u8]);
impl_cmp!(Bytes, &'a [u8]);
impl_cmp!(&'a Bytes, [u8]);
impl_cmp!(Bytes, Vec<u8>);
impl_cmp!(&'a Bytes, Vec<u8>);

impl Hash for Bytes {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(self, state)
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashSet;
    use super::*;

    #[test]
    fn eq() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a1 = Bytes::from(abc);
        let a2 = Bytes::from(abc);
        let d = Bytes::from(def);
        assert_eq!(a1, a2);
        assert_eq!(def, d);
        assert!(a1 != d);
        assert!(a1 != def);
    }

    #[test]
    fn ord() {
        let abc: &[u8] = b"abc";
        let def: &[u8] = b"def";
        let a = Bytes::from(abc);
        let d = Bytes::from(def);
        assert!(a < d);
        assert!(a < def);
        assert!(abc < d);
        assert!(d > a);
        assert!(d > abc);
        assert!(def > a);
    }

    #[test]
    fn hash() {
        let b1 = Bytes::from(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        let b3 = Bytes::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }

    #[test]
    fn from_static() {
        let b1 = Bytes::from_static(b"this is a test");
        let b2 = Bytes::from(b"this is a test");
        assert_eq!(b1, b2);
    }
}
<|endoftext|>


<commit_before>mod checked {
    // Mathematical "errors" we want to catch
    #[derive(Debug)]
    pub enum MathError {
        DivisionByZero,
        NegativeLogarithm,
        NegativeSquareRoot,
    }

    pub type MathResult = Result<f64, MathError>;

    pub fn div(x: f64, y: f64) -> MathResult {
        if y == 0.0 {
            // This operation would `fail`, instead let's return the reason of
            // the failure wrapped in `Err`
            Err(MathError::DivisionByZero)
        } else {
            // This operation is valid, return the result wrapped in `Ok`
            Ok(x / y)
        }
    }

    pub fn sqrt(x: f64) -> MathResult {
        if x < 0.0 {
            Err(MathError::NegativeSquareRoot)
        } else {
            Ok(x.sqrt())
        }
    }

    pub fn ln(x: f64) -> MathResult {
        if x < 0.0 {
            Err(MathError::NegativeLogarithm)
        } else {
            Ok(x.ln())
        }
    }
}

// `op(x, y)` === `sqrt(ln(x / y))`
fn op(x: f64, y: f64) -> f64 {
    // This is a three level match pyramid!
    match checked::div(x, y) {
        Err(why) => panic!("{:?}", why),
        Ok(ratio) => match checked::ln(ratio) {
            Err(why) => panic!("{:?}", why),
            Ok(ln) => match checked::sqrt(ln) {
                Err(why) => panic!("{:?}", why),
                Ok(sqrt) => sqrt,
            },
        },
    }
}

fn main() {
    // Will this fail?
    println!("{}", op(1.0, 10.0));
}
<commit_msg>Transalte examples/std/result/result.rs<commit_after>mod checked {
    // 我们想要捕获的数学“错误”
    #[derive(Debug)]
    pub enum MathError {
        DivisionByZero,
        NegativeLogarithm,
        NegativeSquareRoot,
    }

    pub type MathResult = Result<f64, MathError>;

    pub fn div(x: f64, y: f64) -> MathResult {
        if y == 0.0 {
            // 此操作将会失败，反而让我们返回失败的理由，并装包成 `Err`
            Err(MathError::DivisionByZero)
        } else {
            // 此操作是有效的，返回装包成 `Ok` 的结果
            Ok(x / y)
        }
    }

    pub fn sqrt(x: f64) -> MathResult {
        if x < 0.0 {
            Err(MathError::NegativeSquareRoot)
        } else {
            Ok(x.sqrt())
        }
    }

    pub fn ln(x: f64) -> MathResult {
        if x < 0.0 {
            Err(MathError::NegativeLogarithm)
        } else {
            Ok(x.ln())
        }
    }
}

// `op(x, y)` === `sqrt(ln(x / y))`
fn op(x: f64, y: f64) -> f64 {
    // 这是一个三层的匹配金字塔！
    // （原文：This is a three level match pyramid!）
    match checked::div(x, y) {
        Err(why) => panic!("{:?}", why),
        Ok(ratio) => match checked::ln(ratio) {
            Err(why) => panic!("{:?}", why),
            Ok(ln) => match checked::sqrt(ln) {
                Err(why) => panic!("{:?}", why),
                Ok(sqrt) => sqrt,
            },
        },
    }
}

fn main() {
    // 这会失败吗？
    println!("{}", op(1.0, 10.0));
}
<|endoftext|>


<commit_before>pub struct Chain {
    anchor: Point,
    color: StoneColor,
    stones: PointList,
    liberties: PointList
}

impl Chain {
    pub fn new(point: Point, color: StoneColor) -> Chain {
        Chain {
            anchor: point,
            color: color,
            stones: vec!(point),
            liberties: Vec::new()
        }
    }

    pub fn color(&self) -> StoneColor {
        self.color
    }

    pub fn stones<'a>(&'a self) -> &'a PointList {
        &self.stones
    }

    pub fn stones_mut<'a>(&'a mut self) -> &'a PointList {
        &mut self.stones
    }
}
<commit_msg>removed chain.rs<commit_after><|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! GdkPixbufLoader — Application-driven progressive image loading.

use std;
use ffi;
use glib::{to_bool, GlibContainer, Error};
use glib::translate::ToGlibPtr;
use libc::{c_int, c_uint};

#[repr(C)]
pub struct PixbufLoader {
    pointer: *mut ffi::C_GdkPixbufLoader
}

impl PixbufLoader {
    /// Creates a new pixbuf loader object.
    ///
    /// # Panics
    /// Fails if the pixbuf loader cannot be retrieved.
    pub fn new() -> PixbufLoader {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new() };
        assert!(!tmp.is_null());
        PixbufLoader::wrap_pointer(tmp)
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of type `image_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected type, for loading image formats that can't be
    /// reliably identified by looking at the data, or if the user manually
    /// forces a specific type.
    ///
    /// The list of supported image formats depends on what image loaders are
    /// installed, but typically "png", "jpeg", "gif", "tiff" and "xpm" are
    /// among the supported formats.
    ///
    /// # Failures
    /// Returns an `Error` if the pixbuf loader cannot be created. Query the
    /// error for more detailed information.
    ///
    /// # Panics
    /// Fails if the pixbuf loader cannot be retrieved.
    pub fn new_with_type(image_type: &str) -> Result<PixbufLoader, Error> {
        let mut error = std::ptr::null_mut();
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_type(image_type.borrow_to_glib().0, &mut error) };

        if error.is_null() {
            assert!(!tmp.is_null());
            Ok(PixbufLoader::wrap_pointer(tmp))
        } else {
            Err(Error::wrap(error))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of mime type `mime_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected mime type, for loading image formats that can't
    /// be reliably identified by looking at the data, or if the user manually
    /// forces a specific mime type.
    ///
    /// The list of supported mime types depends on what image loaders are
    /// installed, but typically "image/png", "image/jpeg", "image/gif",
    /// "image/tiff" and "image/x-xpixmap" are among the supported mime types.
    ///
    /// # Failures
    /// Returns an `Error` if the pixbuf loader cannot be created. Query the
    /// error for more detailed information.
    ///
    /// # Panics
    /// Fails if the pixbuf loader cannot be retrieved.
    pub fn new_with_mime_type(mime_type: &str) -> Result<PixbufLoader, Error> {
        let mut error = std::ptr::null_mut();
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_mime_type(mime_type.borrow_to_glib().0, &mut error) };

        if error.is_null() {
            assert!(!tmp.is_null());
            Ok(PixbufLoader::wrap_pointer(tmp))
        } else {
            Err(Error::wrap(error))
        }
    }

    /// Obtains the available information about the format of the currently
    /// loading image file.  Returns `None` if not enough data has been written
    /// to determine the format.
    pub fn get_format(&self) -> Option<::PixbufFormat> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_format(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::PixbufFormat::wrap_pointer(tmp))
        }
    }

    /// This will cause a pixbuf loader to parse the  bytes of an image stored
    /// in `buf`. It will return `Ok` if the data was loaded successfully, and
    /// `Err` if an error occurred. In the latter case, the loader will be
    /// closed, and will not accept further writes.
    ///
    /// # Failures
    /// Returns an `Error` if `buf` cannot be written to the loader.  Query the
    /// `Error` for more detailed information.
    pub fn loader_write(&self, buf: &[u8]) -> Result<(), Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_write(self.unwrap_pointer(), buf.as_ptr(), buf.len() as c_uint, &mut error)) {
                true => Ok(()),
                false => Err(Error::wrap(error))
            }
        }
    }

    /*pub fn loader_write_bytes(&self, buffer: &glib::Bytes, error: &mut Error) -> bool {
      gdk_pixbuf_loader_write_bytes
      }*/

    /// Causes the image to be scaled while it is loaded. The desired image
    /// size can be determined relative to the original size of the image by
    /// calling `set_size()` from a signal handler for the `size-prepared`
    /// signal.
    ///
    /// Attempts to set the desired image size are ignored after the emission
    /// of the `size-prepared` signal.
    pub fn set_size(&self, width: isize, height: isize) {
        unsafe { ffi::gdk_pixbuf_loader_set_size(self.unwrap_pointer(), width as c_int, height as c_int) }
    }

    /// Queries the `Pixbuf` that a pixbuf loader is currently creating. In
    /// general it only makes sense to call this function after the
    /// `area-prepared` signal has been emitted by the loader; this means that
    /// enough data has been read to know the size of the image that will be
    /// allocated. If the loader has not received enough data via
    /// `loader_write()`, then this function returns `None`. If the loader is
    /// an animation, it will return the "static image" of the animation.
    pub fn get_pixbuf(&self) -> Option<::Pixbuf> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_pixbuf(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::Pixbuf::wrap_pointer(tmp))
        }
    }

    /*pub fn get_animation(&self) -> Option<::PixbufAnimation> {
      let tmp = unsafe { ffi::gdk_pixbuf_loader_get_animation(self.unwrap_pointer()) };

      if tmp.is_null() {
      None
      } else {
      Some(::PixbufAnimation::wrap_pointer(tmp))
      }
      }*/

    /// Informs a pixbuf loader that no further writes with `loader_write()`
    /// will occur, so that it can free its internal loading structures. Also,
    /// tries to parse any data that hasn't yet been parsed.
    ///
    /// # Failures
    /// If the remaining data is partial or corrupt, an error will be returned.
    /// Query the `Error` for more detailed information.
    pub fn close(&self) -> Result<(), Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_close(self.unwrap_pointer(), &mut error)) {
                true => Ok(()),
                false => Err(Error::wrap(error))
            }
        }
    }
}

impl_GObjectFunctions!(PixbufLoader, C_GdkPixbufLoader);
<commit_msg>Reverting changes to `PixbufLoader::new()`<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! GdkPixbufLoader — Application-driven progressive image loading.

use std;
use ffi;
use glib::{to_bool, GlibContainer, Error};
use glib::translate::ToGlibPtr;
use libc::{c_int, c_uint};

#[repr(C)]
pub struct PixbufLoader {
    pointer: *mut ffi::C_GdkPixbufLoader
}

impl PixbufLoader {
    /// Creates a new pixbuf loader object.
    ///
    /// # Failures
    /// Returns `None` if the pixbuf loader cannot be created.
    pub fn new() -> Option<PixbufLoader> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new() };

        if tmp.is_null() {
            None
        } else {
            Some(PixbufLoader::wrap_pointer(tmp))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of type `image_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected type, for loading image formats that can't be
    /// reliably identified by looking at the data, or if the user manually
    /// forces a specific type.
    ///
    /// The list of supported image formats depends on what image loaders are
    /// installed, but typically "png", "jpeg", "gif", "tiff" and "xpm" are
    /// among the supported formats.
    ///
    /// # Failures
    /// Returns an `Error` if the pixbuf loader cannot be created. Query the
    /// error for more detailed information.
    ///
    /// # Panics
    /// Fails if the pixbuf loader cannot be retrieved.
    pub fn new_with_type(image_type: &str) -> Result<PixbufLoader, Error> {
        let mut error = std::ptr::null_mut();
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_type(image_type.borrow_to_glib().0, &mut error) };

        if error.is_null() {
            assert!(!tmp.is_null());
            Ok(PixbufLoader::wrap_pointer(tmp))
        } else {
            Err(Error::wrap(error))
        }
    }

    /// Creates a new pixbuf loader object that always attempts to parse image
    /// data as if it were an image of mime type `mime_type`, instead of
    /// identifying the type automatically. Useful if you want an error if the
    /// image isn't the expected mime type, for loading image formats that can't
    /// be reliably identified by looking at the data, or if the user manually
    /// forces a specific mime type.
    ///
    /// The list of supported mime types depends on what image loaders are
    /// installed, but typically "image/png", "image/jpeg", "image/gif",
    /// "image/tiff" and "image/x-xpixmap" are among the supported mime types.
    ///
    /// # Failures
    /// Returns an `Error` if the pixbuf loader cannot be created. Query the
    /// error for more detailed information.
    ///
    /// # Panics
    /// Fails if the pixbuf loader cannot be retrieved.
    pub fn new_with_mime_type(mime_type: &str) -> Result<PixbufLoader, Error> {
        let mut error = std::ptr::null_mut();
        let tmp = unsafe { ffi::gdk_pixbuf_loader_new_with_mime_type(mime_type.borrow_to_glib().0, &mut error) };

        if error.is_null() {
            assert!(!tmp.is_null());
            Ok(PixbufLoader::wrap_pointer(tmp))
        } else {
            Err(Error::wrap(error))
        }
    }

    /// Obtains the available information about the format of the currently
    /// loading image file.  Returns `None` if not enough data has been written
    /// to determine the format.
    pub fn get_format(&self) -> Option<::PixbufFormat> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_format(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::PixbufFormat::wrap_pointer(tmp))
        }
    }

    /// This will cause a pixbuf loader to parse the  bytes of an image stored
    /// in `buf`. It will return `Ok` if the data was loaded successfully, and
    /// `Err` if an error occurred. In the latter case, the loader will be
    /// closed, and will not accept further writes.
    ///
    /// # Failures
    /// Returns an `Error` if `buf` cannot be written to the loader.  Query the
    /// `Error` for more detailed information.
    pub fn loader_write(&self, buf: &[u8]) -> Result<(), Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_write(self.unwrap_pointer(), buf.as_ptr(), buf.len() as c_uint, &mut error)) {
                true => Ok(()),
                false => Err(Error::wrap(error))
            }
        }
    }

    /*pub fn loader_write_bytes(&self, buffer: &glib::Bytes, error: &mut Error) -> bool {
      gdk_pixbuf_loader_write_bytes
      }*/

    /// Causes the image to be scaled while it is loaded. The desired image
    /// size can be determined relative to the original size of the image by
    /// calling `set_size()` from a signal handler for the `size-prepared`
    /// signal.
    ///
    /// Attempts to set the desired image size are ignored after the emission
    /// of the `size-prepared` signal.
    pub fn set_size(&self, width: isize, height: isize) {
        unsafe { ffi::gdk_pixbuf_loader_set_size(self.unwrap_pointer(), width as c_int, height as c_int) }
    }

    /// Queries the `Pixbuf` that a pixbuf loader is currently creating. In
    /// general it only makes sense to call this function after the
    /// `area-prepared` signal has been emitted by the loader; this means that
    /// enough data has been read to know the size of the image that will be
    /// allocated. If the loader has not received enough data via
    /// `loader_write()`, then this function returns `None`. If the loader is
    /// an animation, it will return the "static image" of the animation.
    pub fn get_pixbuf(&self) -> Option<::Pixbuf> {
        let tmp = unsafe { ffi::gdk_pixbuf_loader_get_pixbuf(self.unwrap_pointer()) };

        if tmp.is_null() {
            None
        } else {
            Some(::Pixbuf::wrap_pointer(tmp))
        }
    }

    /*pub fn get_animation(&self) -> Option<::PixbufAnimation> {
      let tmp = unsafe { ffi::gdk_pixbuf_loader_get_animation(self.unwrap_pointer()) };

      if tmp.is_null() {
      None
      } else {
      Some(::PixbufAnimation::wrap_pointer(tmp))
      }
      }*/

    /// Informs a pixbuf loader that no further writes with `loader_write()`
    /// will occur, so that it can free its internal loading structures. Also,
    /// tries to parse any data that hasn't yet been parsed.
    ///
    /// # Failures
    /// If the remaining data is partial or corrupt, an error will be returned.
    /// Query the `Error` for more detailed information.
    pub fn close(&self) -> Result<(), Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            match to_bool(ffi::gdk_pixbuf_loader_close(self.unwrap_pointer(), &mut error)) {
                true => Ok(()),
                false => Err(Error::wrap(error))
            }
        }
    }
}

impl_GObjectFunctions!(PixbufLoader, C_GdkPixbufLoader);
<|endoftext|>