<commit_before>use std::{self,
          env::VarError,
          ffi::{OsStr,
                OsString},
          str::FromStr};

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var(key) {
///     Ok(val) => panic!("The environment variable {} is set but empty!", key),
///     Err(e) => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> std::result::Result<String, VarError> {
    match std::env::var(key) {
        Ok(val) => {
            if val.is_empty() {
                Err(VarError::NotPresent)
            } else {
                Ok(val)
            }
        }
        Err(e) => Err(e),
    }
}

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var_os` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var_os(key) {
///     Some(val) => panic!("The environment variable {} is set but empty!", key),
///     None => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var_os<K: AsRef<OsStr>>(key: K) -> std::option::Option<OsString> {
    match std::env::var_os(key) {
        Some(val) => {
            if val.to_string_lossy().as_ref().is_empty() {
                None
            } else {
                Some(val)
            }
        }
        None => None,
    }
}

/// Declare a struct that implements the `Config` trait with a minimum of boilerplate.
/// This declares a simple newtype struct whose name comes from `$wrapping_type`,
/// which wraps the provided `$wrapped_type` and can be overridden by setting the
/// environment variable specified in `$env_var`.
///
/// Additionally, this macro provides a `From` (and implicitly `Into`) implementation
/// so the `$wrapping_type` can be ergonomically converted to `$wrapped_type`.
///
/// For example, if `$wrapping_type` were `Foo`, to access the overridden value and
/// pass it to a function `bar` which accepts `$wrapped_type`:
///
/// ```ignore
/// bar(Foo::configured_value().into());
/// ```
///
/// See `Config::configured_value`'s documentation for more.
///
/// In general this exists to make the work of other macros which implement wrappers for
/// specific wrapped types simpler since the remaining arguments which specify the
/// `FromStr` implementation will generally be the same for a given wrapped type.
#[macro_export]
macro_rules! env_config {
    (
        #[$attr:meta],
        $vis:vis $wrapping_type:ident,
        $wrapped_type:ty,
        $env_var:ident,
        $default_value:expr,
        $from_str_err_type:ty,
        $from_str_input:ident,
        $from_str_return:expr
    ) => {
        #[allow(unused_imports)]
        use $crate::env::Config as _;

        #[$attr]
        $vis struct $wrapping_type($wrapped_type);
        // A little trickery to avoid env var name collisions:
        // This enum can't ever be instantiated, but the compiler will give
        // an error if two invocations in a namespace give the same env_var.
        // It'd be nice to make this work globally, but I don't see a good way
        #[allow(non_camel_case_types, dead_code)]
        enum $env_var {}

        impl $crate::env::Config for $wrapping_type {
            const ENVVAR: &'static str = stringify!($env_var);
        }

        impl Default for $wrapping_type {
            fn default() -> Self { Self($default_value) }
        }

        impl std::str::FromStr for $wrapping_type {
            type Err = $from_str_err_type;

            fn from_str($from_str_input: &str) -> std::result::Result<Self, Self::Err> {
                $from_str_return
            }
        }

        impl std::convert::From<$wrapping_type> for $wrapped_type {
            fn from(x: $wrapping_type) -> $wrapped_type { x.0 }
        }
    };
}

/// Declare a struct `$wrapping_type` that stores a `std::time::Duration` and
/// implements the `Config` trait so that its value can be overridden by `$env_var_as_secs`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// use std::time::Duration;
/// habitat_core::env_config_duration!(PersistLoopPeriod,
///                                    HAB_PERSIST_LOOP_PERIOD_SECS,
///                                    Duration::from_secs(30));
/// ```
#[macro_export]
macro_rules! env_config_duration {
    ($wrapping_type:ident, $env_var_as_secs:ident, $default_value:expr) => {
        $crate::env_config!(#[derive(Debug)],
                            $wrapping_type,
                            std::time::Duration,
                            $env_var_as_secs,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self(std::time::Duration::from_secs(s.parse()?))));
    };
}

/// Declare a struct `$wrapping_type` that stores an integer of type `$type` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// use std::time::Duration;
/// habitat_core::env_config_duration!(ThreadAliveThreshold,
///                                    HAB_THREAD_ALIVE_THRESHOLD_SECS,
///                                    Duration::from_secs(5 * 60));
/// ```
#[macro_export]
macro_rules! env_config_int {
    (#[$attr:meta], $wrapping_type:ident, $type:ty, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[$attr],
                            $wrapping_type,
                            $type,
                            $env_var,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self((s.parse()?))));
    };

    ($wrapping_type:ident, $type:ty, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[derive(Debug)],
                            $wrapping_type,
                            $type,
                            $env_var,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self((s.parse()?))));
    };
}

/// Declare a struct `$wrapping_type` that stores a `String` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_string!(#[derive(Deserialize, Serialize, Clone, Debug, Eq, Hash, PartialEq)],
///                                  pub ChannelIdent,
///                                  HAB_BLDR_CHANNEL,
///                                  STABLE_CHANNEL_IDENT.to_string());
/// ```
#[macro_export]
macro_rules! env_config_string {
    (#[$attr:meta], $vis:vis $wrapping_type:ident, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[$attr],
                            $vis $wrapping_type,
                            String,
                            $env_var,
                            $default_value,
                            $crate::Impossible,
                            s,
                            Ok(Self(s.to_string())));

        impl std::convert::From<&str> for $wrapping_type {
            fn from(s: &str) -> Self { Self(s.to_string()) }
        }

        impl std::convert::From<String> for $wrapping_type {
            fn from(s: String) -> Self { Self(s) }
        }
    };
}

/// Declare a struct `$wrapping_type` that stores a `SocketAddr` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_socketaddr!(#[derive(Clone, Copy, PartialEq, Eq, Debug)],
///                                      pub ListenCtlAddr,
///                                      HAB_LISTEN_CTL,
///                                      SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, Self::DEFAULT_PORT)));
/// ```
#[macro_export]
macro_rules! env_config_socketaddr {
    (#[$attr:meta], $vis:vis $wrapping_type:ident, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[$attr],
                            $vis $wrapping_type,
                            SocketAddr,
                            $env_var,
                            $default_value,
                            std::net::AddrParseError,
                            val,
                            Ok(val.parse::<SocketAddr>()?.into()));
    };
}

/// Enable the creation of a value based on an environment variable
/// that can be supplied at runtime by the user.
pub trait Config: Default + FromStr {
    /// The environment variable that will be parsed to create an
    /// instance of `Self`.
    const ENVVAR: &'static str;

    /// Generate an instance of `Self` from the value of the
    /// environment variable `Self::ENVVAR`.
    ///
    /// If the environment variable is present and not empty, its
    /// value will be parsed as `Self`. If it cannot be parsed, or the
    /// environment variable is not present, the default value of the
    /// type will be given instead.
    fn configured_value() -> Self {
        match var(Self::ENVVAR) {
            Err(VarError::NotPresent) => Self::default(),
            Ok(val) => {
                match val.parse() {
                    Ok(parsed) => {
                        Self::log_parsable(&val);
                        parsed
                    }
                    Err(_) => {
                        Self::log_unparsable(&val);
                        Self::default()
                    }
                }
            }
            Err(VarError::NotUnicode(nu)) => {
                Self::log_unparsable(nu.to_string_lossy());
                Self::default()
            }
        }
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_parsable(env_value: &str) {
        warn!("Found '{}' in environment; using value '{}'",
              Self::ENVVAR,
              env_value);
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was _not_ successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_unparsable<S>(env_value: S)
        where S: AsRef<str>
    {
        warn!("Found '{}' in environment, but value '{}' was unparsable; using default instead",
              Self::ENVVAR,
              env_value.as_ref());
    }
}
<commit_msg>Fix env_config_int documentation<commit_after>use std::{self,
          env::VarError,
          ffi::{OsStr,
                OsString},
          str::FromStr};

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var(key) {
///     Ok(val) => panic!("The environment variable {} is set but empty!", key),
///     Err(e) => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> std::result::Result<String, VarError> {
    match std::env::var(key) {
        Ok(val) => {
            if val.is_empty() {
                Err(VarError::NotPresent)
            } else {
                Ok(val)
            }
        }
        Err(e) => Err(e),
    }
}

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var_os` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var_os(key) {
///     Some(val) => panic!("The environment variable {} is set but empty!", key),
///     None => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var_os<K: AsRef<OsStr>>(key: K) -> std::option::Option<OsString> {
    match std::env::var_os(key) {
        Some(val) => {
            if val.to_string_lossy().as_ref().is_empty() {
                None
            } else {
                Some(val)
            }
        }
        None => None,
    }
}

/// Declare a struct that implements the `Config` trait with a minimum of boilerplate.
/// This declares a simple newtype struct whose name comes from `$wrapping_type`,
/// which wraps the provided `$wrapped_type` and can be overridden by setting the
/// environment variable specified in `$env_var`.
///
/// Additionally, this macro provides a `From` (and implicitly `Into`) implementation
/// so the `$wrapping_type` can be ergonomically converted to `$wrapped_type`.
///
/// For example, if `$wrapping_type` were `Foo`, to access the overridden value and
/// pass it to a function `bar` which accepts `$wrapped_type`:
///
/// ```ignore
/// bar(Foo::configured_value().into());
/// ```
///
/// See `Config::configured_value`'s documentation for more.
///
/// In general this exists to make the work of other macros which implement wrappers for
/// specific wrapped types simpler since the remaining arguments which specify the
/// `FromStr` implementation will generally be the same for a given wrapped type.
#[macro_export]
macro_rules! env_config {
    (
        #[$attr:meta],
        $vis:vis $wrapping_type:ident,
        $wrapped_type:ty,
        $env_var:ident,
        $default_value:expr,
        $from_str_err_type:ty,
        $from_str_input:ident,
        $from_str_return:expr
    ) => {
        #[allow(unused_imports)]
        use $crate::env::Config as _;

        #[$attr]
        $vis struct $wrapping_type($wrapped_type);
        // A little trickery to avoid env var name collisions:
        // This enum can't ever be instantiated, but the compiler will give
        // an error if two invocations in a namespace give the same env_var.
        // It'd be nice to make this work globally, but I don't see a good way
        #[allow(non_camel_case_types, dead_code)]
        enum $env_var {}

        impl $crate::env::Config for $wrapping_type {
            const ENVVAR: &'static str = stringify!($env_var);
        }

        impl Default for $wrapping_type {
            fn default() -> Self { Self($default_value) }
        }

        impl std::str::FromStr for $wrapping_type {
            type Err = $from_str_err_type;

            fn from_str($from_str_input: &str) -> std::result::Result<Self, Self::Err> {
                $from_str_return
            }
        }

        impl std::convert::From<$wrapping_type> for $wrapped_type {
            fn from(x: $wrapping_type) -> $wrapped_type { x.0 }
        }
    };
}

/// Declare a struct `$wrapping_type` that stores a `std::time::Duration` and
/// implements the `Config` trait so that its value can be overridden by `$env_var_as_secs`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// use std::time::Duration;
/// habitat_core::env_config_duration!(PersistLoopPeriod,
///                                    HAB_PERSIST_LOOP_PERIOD_SECS,
///                                    Duration::from_secs(30));
/// ```
#[macro_export]
macro_rules! env_config_duration {
    ($wrapping_type:ident, $env_var_as_secs:ident, $default_value:expr) => {
        $crate::env_config!(#[derive(Debug)],
                            $wrapping_type,
                            std::time::Duration,
                            $env_var_as_secs,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self(std::time::Duration::from_secs(s.parse()?))));
    };
}

/// Declare a struct `$wrapping_type` that stores an integer of type `$type` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_int!(RecvTimeoutMillis, i32, HAB_PULL_RECV_TIMEOUT_MS, 5_000);
///
/// habitat_core::env_config_int!(#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq)],
///                               TokioThreadCount,
///                               usize,
///                               HAB_TOKIO_THREAD_COUNT,
///                               num_cpus::get().max(1));
/// ```
#[macro_export]
macro_rules! env_config_int {
    (#[$attr:meta], $wrapping_type:ident, $type:ty, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[$attr],
                            $wrapping_type,
                            $type,
                            $env_var,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self((s.parse()?))));
    };

    ($wrapping_type:ident, $type:ty, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[derive(Debug)],
                            $wrapping_type,
                            $type,
                            $env_var,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self((s.parse()?))));
    };
}

/// Declare a struct `$wrapping_type` that stores a `String` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_string!(#[derive(Deserialize, Serialize, Clone, Debug, Eq, Hash, PartialEq)],
///                                  pub ChannelIdent,
///                                  HAB_BLDR_CHANNEL,
///                                  STABLE_CHANNEL_IDENT.to_string());
/// ```
#[macro_export]
macro_rules! env_config_string {
    (#[$attr:meta], $vis:vis $wrapping_type:ident, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[$attr],
                            $vis $wrapping_type,
                            String,
                            $env_var,
                            $default_value,
                            $crate::Impossible,
                            s,
                            Ok(Self(s.to_string())));

        impl std::convert::From<&str> for $wrapping_type {
            fn from(s: &str) -> Self { Self(s.to_string()) }
        }

        impl std::convert::From<String> for $wrapping_type {
            fn from(s: String) -> Self { Self(s) }
        }
    };
}

/// Declare a struct `$wrapping_type` that stores a `SocketAddr` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_socketaddr!(#[derive(Clone, Copy, PartialEq, Eq, Debug)],
///                                      pub ListenCtlAddr,
///                                      HAB_LISTEN_CTL,
///                                      SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, Self::DEFAULT_PORT)));
/// ```
#[macro_export]
macro_rules! env_config_socketaddr {
    (#[$attr:meta], $vis:vis $wrapping_type:ident, $env_var:ident, $default_value:expr) => {
        $crate::env_config!(#[$attr],
                            $vis $wrapping_type,
                            SocketAddr,
                            $env_var,
                            $default_value,
                            std::net::AddrParseError,
                            val,
                            Ok(val.parse::<SocketAddr>()?.into()));
    };
}

/// Enable the creation of a value based on an environment variable
/// that can be supplied at runtime by the user.
pub trait Config: Default + FromStr {
    /// The environment variable that will be parsed to create an
    /// instance of `Self`.
    const ENVVAR: &'static str;

    /// Generate an instance of `Self` from the value of the
    /// environment variable `Self::ENVVAR`.
    ///
    /// If the environment variable is present and not empty, its
    /// value will be parsed as `Self`. If it cannot be parsed, or the
    /// environment variable is not present, the default value of the
    /// type will be given instead.
    fn configured_value() -> Self {
        match var(Self::ENVVAR) {
            Err(VarError::NotPresent) => Self::default(),
            Ok(val) => {
                match val.parse() {
                    Ok(parsed) => {
                        Self::log_parsable(&val);
                        parsed
                    }
                    Err(_) => {
                        Self::log_unparsable(&val);
                        Self::default()
                    }
                }
            }
            Err(VarError::NotUnicode(nu)) => {
                Self::log_unparsable(nu.to_string_lossy());
                Self::default()
            }
        }
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_parsable(env_value: &str) {
        warn!("Found '{}' in environment; using value '{}'",
              Self::ENVVAR,
              env_value);
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was _not_ successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_unparsable<S>(env_value: S)
        where S: AsRef<str>
    {
        warn!("Found '{}' in environment, but value '{}' was unparsable; using default instead",
              Self::ENVVAR,
              env_value.as_ref());
    }
}
<|endoftext|>


<commit_before>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

impl Turn {
    pub fn switch_turns(&mut self) {
        *self = match *self {
            Turn::White => Turn::Black,
            Turn::Black => Turn::White,
        }
    }
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // Conveniently, every other hex has exactly two pieces on it in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Cannot get field on removed hex {:?}", coord),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => hex[coord.f as usize] = field,
            None => panic!("Cannot set field on removed hex {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert_eq!(
            self.get_field(from),
            &Field::Piece,
            "There is no piece at {:?} to move",
            from
        );
        assert!(
            self.get_field_vertex_neighbors(from).contains(to),
            "Cannot move piece at {:?} to non-vertex neighbor {:?}",
            from,
            to
        );
        assert_eq!(
            self.get_field(to),
            &Field::Empty,
            "Cannot move piece at {:?} to occupied neighbor {:?}",
            from,
            to
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex.iter().any(|&f| f == Field::Piece) {
                return false;
            },
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_idxs: Vec<u32> = coord.get_neighbors().iter().map(|&(i, _)| i).collect();
        let neighbor_idxs_slice = neighbor_idxs.as_slice();

        match neighbor_idxs_slice.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            self.get_hex_neighbors(coord).len(),
        );
        self.set_hex(coord, None);
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                let coord = HexCoord::new(x, y);
                if (x + y).abs() <= 2 && self.get_hex(&coord).is_some() {
                    coords.push(coord);
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<commit_msg>Rename Model::init to Model::new<commit_after>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

impl Turn {
    pub fn switch_turns(&mut self) {
        *self = match *self {
            Turn::White => Turn::Black,
            Turn::Black => Turn::White,
        }
    }
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // Conveniently, every other hex has exactly two pieces on it in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Cannot get field on removed hex {:?}", coord),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => hex[coord.f as usize] = field,
            None => panic!("Cannot set field on removed hex {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert_eq!(
            self.get_field(from),
            &Field::Piece,
            "There is no piece at {:?} to move",
            from
        );
        assert!(
            self.get_field_vertex_neighbors(from).contains(to),
            "Cannot move piece at {:?} to non-vertex neighbor {:?}",
            from,
            to
        );
        assert_eq!(
            self.get_field(to),
            &Field::Empty,
            "Cannot move piece at {:?} to occupied neighbor {:?}",
            from,
            to
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex.iter().any(|&f| f == Field::Piece) {
                return false;
            },
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_idxs: Vec<u32> = coord.get_neighbors().iter().map(|&(i, _)| i).collect();
        let neighbor_idxs_slice = neighbor_idxs.as_slice();

        match neighbor_idxs_slice.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            self.get_hex_neighbors(coord).len(),
        );
        self.set_hex(coord, None);
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                let coord = HexCoord::new(x, y);
                if (x + y).abs() <= 2 && self.get_hex(&coord).is_some() {
                    coords.push(coord);
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<|endoftext|>


<commit_before>
pub mod ll {
    use std::libc::{c_int, c_uint, c_void, uint8_t, uint32_t};
    use surface::ll::SDL_Surface;
    use video::ll::SDL_Window;

    pub type SDL_bool = c_int;
    pub type SDL_Cursor = c_void;

    pub type SDL_SystemCursor = c_uint;
    pub static SDL_SYSTEM_CURSOR_ARROW: SDL_SystemCursor = 0;
    pub static SDL_SYSTEM_CURSOR_IBEAM: SDL_SystemCursor = 1;
    pub static SDL_SYSTEM_CURSOR_WAIT: SDL_SystemCursor = 2;
    pub static SDL_SYSTEM_CURSOR_CROSSHAIR: SDL_SystemCursor = 3;
    pub static SDL_SYSTEM_CURSOR_WAITARROW: SDL_SystemCursor = 4;
    pub static SDL_SYSTEM_CURSOR_SIZENWSE: SDL_SystemCursor = 5;
    pub static SDL_SYSTEM_CURSOR_SIZENESW: SDL_SystemCursor = 6;
    pub static SDL_SYSTEM_CURSOR_SIZEWE: SDL_SystemCursor = 7;
    pub static SDL_SYSTEM_CURSOR_SIZENS: SDL_SystemCursor = 8;
    pub static SDL_SYSTEM_CURSOR_SIZEALL: SDL_SystemCursor = 9;
    pub static SDL_SYSTEM_CURSOR_NO: SDL_SystemCursor = 10;
    pub static SDL_SYSTEM_CURSOR_HAND: SDL_SystemCursor = 11;
    pub static SDL_NUM_SYSTEM_CURSORS: SDL_SystemCursor = 12;

    pub type SDL_MouseState = c_int;
    pub static SDL_DISABLE: SDL_MouseState = 0;
    pub static SDL_ENABLE: SDL_MouseState = 1;
    pub static SDL_QUERY: SDL_MouseState = -1;

    externfn!(fn SDL_GetMouseFocus() -> *SDL_Window)
    externfn!(fn SDL_GetMouseState(x: *c_int, y: *c_int) -> uint32_t)
    externfn!(fn SDL_GetRelativeMouseState(x: *c_int, y: *c_int) -> uint32_t)
    externfn!(fn SDL_WarpMouseInWindow(window: *SDL_Window, x: c_int, y: c_int))
    externfn!(fn SDL_SetRelativeMouseMode(enabled: SDL_bool) -> c_int)
    externfn!(fn SDL_GetRelativeMouseMode() -> SDL_bool)
    externfn!(fn SDL_CreateCursor(data: *uint8_t, mask: *uint8_t, w: c_int,
                                  h: c_int, hot_x: c_int, hot_y: c_int) ->
              *SDL_Cursor)
    externfn!(fn SDL_CreateColorCursor(surface: *SDL_Surface, hot_x: c_int,
                                       hot_y: c_int) -> *SDL_Cursor)
    externfn!(fn SDL_CreateSystemCursor(id: SDL_SystemCursor) -> *SDL_Cursor)
    externfn!(fn SDL_SetCursor(cursor: *SDL_Cursor))
    externfn!(fn SDL_GetCursor() -> *SDL_Cursor)
    externfn!(fn SDL_GetDefaultCursor() -> *SDL_Cursor)
    externfn!(fn SDL_FreeCursor(cursor: *SDL_Cursor))
    externfn!(fn SDL_ShowCursor(toggle: SDL_MouseState) -> SDL_MouseState)
}

#[deriving(Eq)]
pub enum Mouse {
    LeftMouse,
    MiddleMouse,
    RightMouse,
    X1Mouse,
    X2Mouse,
}

#[deriving(Eq)]
pub enum MouseState {
    LeftMouseState = 1,
    MiddleMouseState,
    RightMouseState,
    X1MouseState,
    X2MouseState,
}

pub fn wrap_mouse(bitflags: u8) -> Mouse {
    match bitflags {
        1 => LeftMouse,
        2 => MiddleMouse,
        3 => RightMouse,
        4 => X1Mouse,
        5 => X2Mouse,
        _ => fail!(~"unhandled mouse type")
    }
}

pub fn wrap_mouse_state(bitflags: u32) -> ~[MouseState] {
    let flags = [LeftMouseState,
        MiddleMouseState,
        RightMouseState,
        X1MouseState,
        X2MouseState];

    do flags.iter().filter_map |&flag| {
        if bitflags & (flag as u32) != 0 { Some(flag) }
        else { None }
    }.collect()
}
<commit_msg>Add mouse and cursor API<commit_after>use std::ptr;
use std::vec;

use get_error;
use surface;
use video;

pub mod ll {
    use std::libc::{c_int, c_uint, c_void, uint8_t, uint32_t};
    use surface::ll::SDL_Surface;
    use video::ll::SDL_Window;

    pub type SDL_bool = c_int;
    pub type SDL_Cursor = c_void;

    pub type SDL_SystemCursor = c_uint;
    pub static SDL_SYSTEM_CURSOR_ARROW: SDL_SystemCursor = 0;
    pub static SDL_SYSTEM_CURSOR_IBEAM: SDL_SystemCursor = 1;
    pub static SDL_SYSTEM_CURSOR_WAIT: SDL_SystemCursor = 2;
    pub static SDL_SYSTEM_CURSOR_CROSSHAIR: SDL_SystemCursor = 3;
    pub static SDL_SYSTEM_CURSOR_WAITARROW: SDL_SystemCursor = 4;
    pub static SDL_SYSTEM_CURSOR_SIZENWSE: SDL_SystemCursor = 5;
    pub static SDL_SYSTEM_CURSOR_SIZENESW: SDL_SystemCursor = 6;
    pub static SDL_SYSTEM_CURSOR_SIZEWE: SDL_SystemCursor = 7;
    pub static SDL_SYSTEM_CURSOR_SIZENS: SDL_SystemCursor = 8;
    pub static SDL_SYSTEM_CURSOR_SIZEALL: SDL_SystemCursor = 9;
    pub static SDL_SYSTEM_CURSOR_NO: SDL_SystemCursor = 10;
    pub static SDL_SYSTEM_CURSOR_HAND: SDL_SystemCursor = 11;
    pub static SDL_NUM_SYSTEM_CURSORS: SDL_SystemCursor = 12;

    pub type SDL_MouseState = c_int;
    pub static SDL_DISABLE: SDL_MouseState = 0;
    pub static SDL_ENABLE: SDL_MouseState = 1;
    pub static SDL_QUERY: SDL_MouseState = -1;

    externfn!(fn SDL_GetMouseFocus() -> *SDL_Window)
    externfn!(fn SDL_GetMouseState(x: *c_int, y: *c_int) -> uint32_t)
    externfn!(fn SDL_GetRelativeMouseState(x: *c_int, y: *c_int) -> uint32_t)
    externfn!(fn SDL_WarpMouseInWindow(window: *SDL_Window, x: c_int, y: c_int))
    externfn!(fn SDL_SetRelativeMouseMode(enabled: SDL_bool) -> c_int)
    externfn!(fn SDL_GetRelativeMouseMode() -> SDL_bool)
    externfn!(fn SDL_CreateCursor(data: *uint8_t, mask: *uint8_t, w: c_int,
                                  h: c_int, hot_x: c_int, hot_y: c_int) ->
              *SDL_Cursor)
    externfn!(fn SDL_CreateColorCursor(surface: *SDL_Surface, hot_x: c_int,
                                       hot_y: c_int) -> *SDL_Cursor)
    externfn!(fn SDL_CreateSystemCursor(id: SDL_SystemCursor) -> *SDL_Cursor)
    externfn!(fn SDL_SetCursor(cursor: *SDL_Cursor))
    externfn!(fn SDL_GetCursor() -> *SDL_Cursor)
    externfn!(fn SDL_GetDefaultCursor() -> *SDL_Cursor)
    externfn!(fn SDL_FreeCursor(cursor: *SDL_Cursor))
    externfn!(fn SDL_ShowCursor(toggle: SDL_MouseState) -> SDL_MouseState)
}

#[deriving(Eq)]
pub enum SystemCursor {
    ArrowCursor = ll::SDL_SYSTEM_CURSOR_ARROW,
    IBeamCursor = ll::SDL_SYSTEM_CURSOR_IBEAM,
    WaitCursor = ll::SDL_SYSTEM_CURSOR_WAIT,
    CrosshairCursor = ll::SDL_SYSTEM_CURSOR_CROSSHAIR,
    WaitArrowCursor = ll::SDL_SYSTEM_CURSOR_WAITARROW,
    SizeNWSECursor = ll::SDL_SYSTEM_CURSOR_SIZENWSE,
    SizeNESWCursor = ll::SDL_SYSTEM_CURSOR_SIZENESW,
    SizeWECursor = ll::SDL_SYSTEM_CURSOR_SIZEWE,
    SizeNSCursor = ll::SDL_SYSTEM_CURSOR_SIZENS,
    SizeAllCursor = ll::SDL_SYSTEM_CURSOR_SIZEALL,
    NoCursor = ll::SDL_SYSTEM_CURSOR_NO,
    HandCursor = ll::SDL_SYSTEM_CURSOR_HAND,
}

#[deriving(Eq)]
pub struct Cursor {
    raw: *ll::SDL_Cursor,
    owned: bool
}

impl Drop for Cursor {
    fn drop(&self) {
        if self.owned {
            unsafe {
                ll::SDL_FreeCursor(self.raw);
            }
        }
    }
}

impl Cursor {
    pub fn new(data: &[u8], mask: &[u8], width: int, height: int, hot_x: int, hot_y: int) -> Result<~Cursor, ~str> {
        unsafe {
            let raw = ll::SDL_CreateCursor(vec::raw::to_ptr(data),
                                           vec::raw::to_ptr(mask),
                                           width as i32, height as i32,
                                           hot_x as i32, hot_y as i32);

            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Cursor{ raw: raw, owned: true })
            }
        }
    }

    pub fn from_surface(surface: surface::Surface, hot_x: int, hot_y: int) -> Result<~Cursor, ~str> {
        unsafe {
            let raw = ll::SDL_CreateColorCursor(surface.raw, hot_x as i32,
                                                hot_y as i32);

            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Cursor{ raw: raw, owned: true })
            }
        }
    }

    pub fn from_system(cursor: SystemCursor) -> Result<~Cursor, ~str> {
        unsafe {
            let raw = ll::SDL_CreateSystemCursor(cursor as u32);

            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Cursor{ raw: raw, owned: true })
            }
        }
    }

    pub fn set(&self) {
        unsafe { ll::SDL_SetCursor(self.raw); }
    }
}

#[deriving(Eq)]
pub enum Mouse {
    LeftMouse,
    MiddleMouse,
    RightMouse,
    X1Mouse,
    X2Mouse,
}

#[deriving(Eq)]
pub enum MouseState {
    LeftMouseState = 1,
    MiddleMouseState = 2,
    RightMouseState = 4,
    X1MouseState = 8,
    X2MouseState = 16,
}

pub fn wrap_mouse(bitflags: u8) -> Mouse {
    match bitflags {
        1 => LeftMouse,
        2 => MiddleMouse,
        3 => RightMouse,
        4 => X1Mouse,
        5 => X2Mouse,
        _ => fail!(~"unhandled mouse type")
    }
}

pub fn wrap_mouse_state(bitflags: u32) -> ~[MouseState] {
    let flags = [LeftMouseState,
        MiddleMouseState,
        RightMouseState,
        X1MouseState,
        X2MouseState];

    do flags.iter().filter_map |&flag| {
        if bitflags & (flag as u32) != 0 { Some(flag) }
        else { None }
    }.collect()
}

pub fn get_mouse_focus() -> Result<~video::Window, ~str> {
    let raw = unsafe { ll::SDL_GetMouseFocus() };
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(~video::Window{ raw: raw, owned: false })
    }
}

pub fn get_mouse_state() -> (~[MouseState], int, int) {
    let x = 0;
    let y = 0;
    let raw = unsafe { ll::SDL_GetMouseState(&x, &y) };

    return (wrap_mouse_state(raw), x as int, y as int);
}

pub fn get_relative_mouse_state() -> (~[MouseState], int, int) {
    let x = 0;
    let y = 0;
    let raw = unsafe { ll::SDL_GetRelativeMouseState(&x, &y) };

    return (wrap_mouse_state(raw), x as int, y as int);
}

pub fn warp_mouse_in_window(window: &video::Window, x: i32, y: i32) {
    unsafe { ll::SDL_WarpMouseInWindow(window.raw, x, y); }
}

pub fn set_relative_mouse_mode(on: bool) {
    unsafe { ll::SDL_SetRelativeMouseMode(on as i32); }
}

pub fn get_relative_mouse_mode() -> bool {
    unsafe { ll::SDL_GetRelativeMouseMode() == 1 }
}

pub fn get_cursor() -> Option<~Cursor> {
    let raw = unsafe { ll::SDL_GetCursor() };

    if raw == ptr::null() {
        None
    } else {
        Some(~Cursor { raw: raw, owned: false })
    }
}

pub fn get_default_cursor() -> Option<~Cursor> {
    let raw = unsafe { ll::SDL_GetDefaultCursor() };

    if raw == ptr::null() {
        None
    } else {
        Some(~Cursor { raw: raw, owned: false })
    }
}

pub fn is_cursor_showing() -> bool {
    unsafe { ll::SDL_ShowCursor(ll::SDL_QUERY) == 1 }
}

pub fn show_cursor(show: bool) {
    unsafe { ll::SDL_ShowCursor(show as i32); }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io;
use std::ops::{Deref, DerefMut};

use memmap::{Protection, Mmap};

pub struct Pfile {
    inner: Mmap,
}

impl Pfile {
    pub fn with(path: &str) -> io::Result<Self> {
        let inner = Mmap::open_path(path, Protection::Read)?;
        Ok(Pfile { inner: inner })
    }
    pub fn new(fd: File) -> io::Result<Self> {
        let inner = Mmap::open(&fd, Protection::Read)?;
        Ok(Pfile { inner: inner })
    }

    pub fn new2(fd: File) -> io::Result<Self> {
        let inner = Mmap::open(&fd, Protection::ReadWrite)?;
        Ok(Pfile { inner: inner })
    }

    pub fn len(&self) -> usize {
        unsafe { self.inner.as_slice().len() }
    }
}

impl AsRef<[u8]> for Pfile {
    fn as_ref (&self) -> &[u8] {
        unsafe { self.inner.as_slice() }
    }
}

impl AsMut<[u8]> for Pfile {
    fn as_mut (&mut self) -> &mut [u8] {
        unsafe { self.inner.as_mut_slice() }
    }
}

impl Deref for Pfile {
    type Target = [u8];
    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { self.inner.as_slice() }
    }
}

impl DerefMut for Pfile {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.inner.as_mut_slice() }
    }
}
<commit_msg>scroll: remove unused pfile<commit_after><|endoftext|>


<commit_before>use frappe::{Signal, Sink, Stream};
use std::fmt::Debug;
use std::sync::{Arc, RwLock};

#[test]
fn stream_operations() {
    let sink: Sink<i32> = Sink::new();
    let stream = sink.stream();

    let s_string = stream.map(|a| a.to_string()).collect::<Vec<_>>();
    let s_odd = stream.filter(|a| a % 2 != 0).collect::<Vec<_>>();
    let s_even_half = stream
        .filter_map(|a| if *a % 2 == 0 { Some(*a / 2) } else { None })
        .collect::<Vec<_>>();
    let (pos, neg) = stream
        .map(|a| if *a > 0 { Ok(*a) } else { Err(*a) })
        .split();
    let s_pos = pos.collect::<Vec<_>>();
    let s_neg = neg.collect::<Vec<_>>();
    let s_merged = pos.merge(&neg.map(|a| -*a)).collect::<Vec<_>>();
    let s_accum = stream
        .collect::<Vec<_>>()
        .snapshot(&stream, |s, _| s)
        .collect::<Vec<_>>();
    let s_cloned = stream.fold_clone(vec![], |mut a, v| {
        a.push(v.into_owned());
        a
    });
    let s_last_pos = stream.hold_if(0, |a| *a > 0);

    sink.feed(&[5, 8, 13, -2, 42, -33]);

    assert_eq!(s_string.sample(), ["5", "8", "13", "-2", "42", "-33"]);
    assert_eq!(s_odd.sample(), [5, 13, -33]);
    assert_eq!(s_even_half.sample(), [4, -1, 21]);
    assert_eq!(s_pos.sample(), [5, 8, 13, 42]);
    assert_eq!(s_neg.sample(), [-2, -33]);
    assert_eq!(s_merged.sample(), [5, 8, 13, 2, 42, 33]);
    assert_eq!(
        s_accum.sample(),
        [
            vec![5],
            vec![5, 8],
            vec![5, 8, 13],
            vec![5, 8, 13, -2],
            vec![5, 8, 13, -2, 42],
            vec![5, 8, 13, -2, 42, -33]
        ]
    );
    assert_eq!(s_cloned.sample(), [5, 8, 13, -2, 42, -33]);
    assert_eq!(s_last_pos.sample(), 42);
}

#[test]
fn merge_with() {
    let sink1: Sink<i32> = Sink::new();
    let sink2: Sink<f32> = Sink::new();
    let stream = sink1
        .stream()
        .merge_with(&sink2.stream(), |l| Ok(*l), |r| Err(*r));
    let result = stream.collect::<Vec<_>>();

    sink1.send(1);
    sink2.send(2.0);
    sink1.send(3);
    sink1.send(4);
    sink2.send(5.0);

    assert_eq!(result.sample(), [Ok(1), Err(2.0), Ok(3), Ok(4), Err(5.0)]);
}

#[test]
fn stream_channel() {
    use std::sync::mpsc::channel;

    let sink = Sink::new();
    let input = sink.stream().as_channel();
    let (output, result) = channel();
    let s_result = Signal::from_channel(0, result);

    let thread = std::thread::spawn(move || {
        let sink2 = Sink::new();
        let stream = sink2.stream();
        let s_sum = stream.fold(0, |a, n| a + *n);
        let doubles = stream.map(|n| *n * 2);
        let rx_doubles = doubles.as_channel();

        sink2.feed(input);

        output.send(s_sum.sample()).unwrap();
        rx_doubles
    });

    assert_eq!(s_result.sample(), 0);

    sink.feed(1..100);
    drop(sink);

    let doubles = thread.join().unwrap();
    let s_doubles = Signal::fold_channel(0, doubles, |a, n| a + n);
    assert_eq!(s_result.sample(), 4950);
    assert_eq!(s_doubles.sample(), 9900);
}

#[test]
fn signal_switch() {
    let signal_sink = Sink::new();
    let switched = signal_sink.stream().hold(Default::default()).switch();
    let double = switched.map(|a| a * 2);

    signal_sink.send(Signal::constant(1));
    assert_eq!(switched.sample(), 1);
    assert_eq!(double.sample(), 2);

    signal_sink.send(Signal::from_fn(|| 12));
    assert_eq!(switched.sample(), 12);
    assert_eq!(double.sample(), 24);
}

#[test]
fn cloning() {
    #[derive(Debug, Default)]
    struct Storage<T>(Vec<T>);

    impl<T> Storage<T> {
        fn new() -> Self {
            Storage(Vec::new())
        }
        fn push(mut self, a: T) -> Self {
            self.0.push(a);
            self
        }
    }

    impl<T: Debug> Clone for Storage<T> {
        fn clone(&self) -> Self {
            panic!("storage cloned! {:?}", self.0)
        }
    }

    let sink = Sink::new();
    let accum = sink.stream().fold(Storage::new(), |a, v| a.push(*v));

    sink.feed(0..5);
    assert_eq!(accum.take().0, [0, 1, 2, 3, 4]);
}

#[test]
fn filter_extra() {
    let sink = Sink::new();
    let stream = sink.stream();
    let sign_res = stream.map(|a| if *a >= 0 { Ok(*a) } else { Err(*a) });
    let even_opt = stream.map(|a| if *a % 2 == 0 { Some(*a) } else { None });
    let s_even = even_opt.filter_some().collect::<Vec<_>>();
    let s_pos = sign_res.filter_first().collect::<Vec<_>>();
    let s_neg = sign_res.filter_second().collect::<Vec<_>>();

    sink.feed(vec![1, 8, -3, 42, -66]);

    assert_eq!(s_even.sample(), [8, 42, -66]);
    assert_eq!(s_pos.sample(), [1, 8, 42]);
    assert_eq!(s_neg.sample(), [-3, -66]);
}

#[test]
fn reentrant() {
    let sink = Sink::new();
    let cloned = sink.clone();
    let sig = sink
        .stream()
        .filter_map(move |n| {
            if *n < 10 {
                cloned.send(*n + 1);
                None
            } else {
                Some(*n)
            }
        })
        .hold(0);

    sink.send(1);
    assert_eq!(sig.sample(), 10);
}

#[allow(unused_variables)]
#[test]
fn deletion() {
    fn stream_cell(src: &Stream<i32>, i: i32) -> (Stream<i32>, Arc<RwLock<i32>>) {
        let cell = Arc::new(RwLock::new(0));
        let cloned = cell.clone();
        let stream = src
            .map(move |n| *n + i)
            .inspect(move |n| *cloned.write().unwrap() = *n);
        (stream, cell)
    }

    let sink = Sink::new();
    let stream = sink.stream();
    let (s1, c1) = stream_cell(&stream, 1);
    let (s2, c2) = stream_cell(&stream, 2);
    let (s3, c3) = stream_cell(&stream, 3);

    sink.send(10);
    assert_eq!(*c1.read().unwrap(), 11);
    assert_eq!(*c2.read().unwrap(), 12);
    assert_eq!(*c3.read().unwrap(), 13);

    drop(s2);
    sink.send(20);
    assert_eq!(*c1.read().unwrap(), 21);
    assert_eq!(*c2.read().unwrap(), 12);
    assert_eq!(*c3.read().unwrap(), 23);
}

#[test]
fn map_n() {
    let sink = Sink::new();
    let s_out = sink
        .stream()
        .map_n(|a, sender| {
            for _ in 0..*a {
                sender.send(*a)
            }
        })
        .collect::<Vec<_>>();

    sink.feed(0..4);

    assert_eq!(s_out.sample(), [1, 2, 2, 3, 3, 3]);
}

#[test]
fn stream_collect() {
    use std::cmp::Ordering;
    use std::collections::*;

    let sink: Sink<i32> = Sink::new();
    let stream = sink.stream();
    let s_vec: Signal<Vec<_>> = stream.collect();
    let s_vecdq: Signal<VecDeque<_>> = stream.collect();
    let s_list: Signal<LinkedList<_>> = stream.collect();
    let s_set: Signal<BTreeSet<_>> = stream.collect();
    let s_string: Signal<String> = stream.map(|v| format!("{} ", v)).collect();

    sink.feed(&[1, 3, -42, 2]);

    assert_eq!(s_vec.sample(), [1, 3, -42, 2]);
    assert_eq!(s_vecdq.sample(), [1, 3, -42, 2]);
    assert_eq!(
        s_list.sample().iter().cmp([1, 3, -42, 2].iter()),
        Ordering::Equal
    );
    assert_eq!(
        s_set.sample().iter().cmp([-42, 1, 2, 3].iter()),
        Ordering::Equal
    );
    assert_eq!(s_string.sample(), "1 3 -42 2 ");

    let sink = Sink::new();
    let s_string: Signal<String> = sink.stream().collect();

    sink.feed("abZc".chars());

    assert_eq!(s_string.sample(), "abZc");
}

#[test]
fn signal_chain() {
    let sink = Sink::new();

    let sig_a = sink.stream().hold(0);
    let sig_b = sig_a.map(move |a| a + 1);
    let sig_c = sig_b.map(|a| a * 2);
    let sig_d = sig_c.map(|a| format!("({})", a));
    let sig_e = sig_d.map(|s| s + ".-");

    assert_eq!(sig_e.sample(), "(2).-");
    assert_eq!(sig_e.sample(), "(2).-");

    sink.send(42);

    assert_eq!(sig_e.sample(), "(86).-");
    assert_eq!(sig_e.sample(), "(86).-");
}

#[test]
fn signal_take() {
    #[derive(Debug, Clone, PartialEq, Eq, Default)]
    struct Value(i32);

    let sink = Sink::new();

    let sig = sink.stream().hold(Value(0)).map(|v| Value(v.0 + 1));

    sink.send(Value(41));

    assert_eq!(sig.clone().take(), Value(42));
    assert_eq!(sig.take(), Value(42));
}

#[test]
fn signal_threading() {
    let sink = Sink::new();
    let sig = sink.stream().hold(0);
    sink.send(2);

    let threads: Vec<_> = (0..6)
        .map(|i| {
            let sig_ = sig.clone();
            std::thread::spawn(move || sig_.map(move |x: i32| x.pow(i)).sample())
        })
        .collect();

    let result: Vec<_> = threads.into_iter().map(|th| th.join().unwrap()).collect();
    assert_eq!(result, [1, 2, 4, 8, 16, 32]);
}

#[test]
fn stream_threading() {
    let sink = Sink::new();
    let sig = sink.stream().map(|x| *x + 1).fold(1, |a, x| a * *x);

    let threads: Vec<_> = (0..6)
        .map(|i| {
            let sink_ = sink.clone();
            std::thread::spawn(move || sink_.send(i))
        })
        .collect();

    for th in threads {
        th.join().unwrap();
    }

    assert_eq!(sig.sample(), 720);
}

#[test]
fn send_non_sync() {
    use std::cell::Cell;

    let sink: Sink<Cell<_>> = Sink::new();
    let sig = sink
        .stream()
        .map(|x| Cell::new(x.get() * 2))
        .hold(Default::default())
        .map(|x| Cell::new(x.get() + 2));

    sink.send(Cell::new(20));

    assert_eq!(sig.sample(), Cell::new(42));
}
<commit_msg>moved use statements in tests<commit_after>use frappe::{Signal, Sink, Stream};

#[test]
fn stream_operations() {
    let sink: Sink<i32> = Sink::new();
    let stream = sink.stream();

    let s_string = stream.map(|a| a.to_string()).collect::<Vec<_>>();
    let s_odd = stream.filter(|a| a % 2 != 0).collect::<Vec<_>>();
    let s_even_half = stream
        .filter_map(|a| if *a % 2 == 0 { Some(*a / 2) } else { None })
        .collect::<Vec<_>>();
    let (pos, neg) = stream
        .map(|a| if *a > 0 { Ok(*a) } else { Err(*a) })
        .split();
    let s_pos = pos.collect::<Vec<_>>();
    let s_neg = neg.collect::<Vec<_>>();
    let s_merged = pos.merge(&neg.map(|a| -*a)).collect::<Vec<_>>();
    let s_accum = stream
        .collect::<Vec<_>>()
        .snapshot(&stream, |s, _| s)
        .collect::<Vec<_>>();
    let s_cloned = stream.fold_clone(vec![], |mut a, v| {
        a.push(v.into_owned());
        a
    });
    let s_last_pos = stream.hold_if(0, |a| *a > 0);

    sink.feed(&[5, 8, 13, -2, 42, -33]);

    assert_eq!(s_string.sample(), ["5", "8", "13", "-2", "42", "-33"]);
    assert_eq!(s_odd.sample(), [5, 13, -33]);
    assert_eq!(s_even_half.sample(), [4, -1, 21]);
    assert_eq!(s_pos.sample(), [5, 8, 13, 42]);
    assert_eq!(s_neg.sample(), [-2, -33]);
    assert_eq!(s_merged.sample(), [5, 8, 13, 2, 42, 33]);
    assert_eq!(
        s_accum.sample(),
        [
            vec![5],
            vec![5, 8],
            vec![5, 8, 13],
            vec![5, 8, 13, -2],
            vec![5, 8, 13, -2, 42],
            vec![5, 8, 13, -2, 42, -33]
        ]
    );
    assert_eq!(s_cloned.sample(), [5, 8, 13, -2, 42, -33]);
    assert_eq!(s_last_pos.sample(), 42);
}

#[test]
fn merge_with() {
    let sink1: Sink<i32> = Sink::new();
    let sink2: Sink<f32> = Sink::new();
    let stream = sink1
        .stream()
        .merge_with(&sink2.stream(), |l| Ok(*l), |r| Err(*r));
    let result = stream.collect::<Vec<_>>();

    sink1.send(1);
    sink2.send(2.0);
    sink1.send(3);
    sink1.send(4);
    sink2.send(5.0);

    assert_eq!(result.sample(), [Ok(1), Err(2.0), Ok(3), Ok(4), Err(5.0)]);
}

#[test]
fn stream_channel() {
    use std::sync::mpsc::channel;

    let sink = Sink::new();
    let input = sink.stream().as_channel();
    let (output, result) = channel();
    let s_result = Signal::from_channel(0, result);

    let thread = std::thread::spawn(move || {
        let sink2 = Sink::new();
        let stream = sink2.stream();
        let s_sum = stream.fold(0, |a, n| a + *n);
        let doubles = stream.map(|n| *n * 2);
        let rx_doubles = doubles.as_channel();

        sink2.feed(input);

        output.send(s_sum.sample()).unwrap();
        rx_doubles
    });

    assert_eq!(s_result.sample(), 0);

    sink.feed(1..100);
    drop(sink);

    let doubles = thread.join().unwrap();
    let s_doubles = Signal::fold_channel(0, doubles, |a, n| a + n);
    assert_eq!(s_result.sample(), 4950);
    assert_eq!(s_doubles.sample(), 9900);
}

#[test]
fn signal_switch() {
    let signal_sink = Sink::new();
    let switched = signal_sink.stream().hold(Default::default()).switch();
    let double = switched.map(|a| a * 2);

    signal_sink.send(Signal::constant(1));
    assert_eq!(switched.sample(), 1);
    assert_eq!(double.sample(), 2);

    signal_sink.send(Signal::from_fn(|| 12));
    assert_eq!(switched.sample(), 12);
    assert_eq!(double.sample(), 24);
}

#[test]
fn cloning() {
    use std::fmt::Debug;

    #[derive(Debug, Default)]
    struct Storage<T>(Vec<T>);

    impl<T> Storage<T> {
        fn new() -> Self {
            Storage(Vec::new())
        }
        fn push(mut self, a: T) -> Self {
            self.0.push(a);
            self
        }
    }

    impl<T: Debug> Clone for Storage<T> {
        fn clone(&self) -> Self {
            panic!("storage cloned! {:?}", self.0)
        }
    }

    let sink = Sink::new();
    let accum = sink.stream().fold(Storage::new(), |a, v| a.push(*v));

    sink.feed(0..5);
    assert_eq!(accum.take().0, [0, 1, 2, 3, 4]);
}

#[test]
fn filter_extra() {
    let sink = Sink::new();
    let stream = sink.stream();
    let sign_res = stream.map(|a| if *a >= 0 { Ok(*a) } else { Err(*a) });
    let even_opt = stream.map(|a| if *a % 2 == 0 { Some(*a) } else { None });
    let s_even = even_opt.filter_some().collect::<Vec<_>>();
    let s_pos = sign_res.filter_first().collect::<Vec<_>>();
    let s_neg = sign_res.filter_second().collect::<Vec<_>>();

    sink.feed(vec![1, 8, -3, 42, -66]);

    assert_eq!(s_even.sample(), [8, 42, -66]);
    assert_eq!(s_pos.sample(), [1, 8, 42]);
    assert_eq!(s_neg.sample(), [-3, -66]);
}

#[test]
fn reentrant() {
    let sink = Sink::new();
    let cloned = sink.clone();
    let sig = sink
        .stream()
        .filter_map(move |n| {
            if *n < 10 {
                cloned.send(*n + 1);
                None
            } else {
                Some(*n)
            }
        })
        .hold(0);

    sink.send(1);
    assert_eq!(sig.sample(), 10);
}

#[allow(unused_variables)]
#[test]
fn deletion() {
    use std::sync::{Arc, RwLock};

    fn stream_cell(src: &Stream<i32>, i: i32) -> (Stream<i32>, Arc<RwLock<i32>>) {
        let cell = Arc::new(RwLock::new(0));
        let cloned = cell.clone();
        let stream = src
            .map(move |n| *n + i)
            .inspect(move |n| *cloned.write().unwrap() = *n);
        (stream, cell)
    }

    let sink = Sink::new();
    let stream = sink.stream();
    let (s1, c1) = stream_cell(&stream, 1);
    let (s2, c2) = stream_cell(&stream, 2);
    let (s3, c3) = stream_cell(&stream, 3);

    sink.send(10);
    assert_eq!(*c1.read().unwrap(), 11);
    assert_eq!(*c2.read().unwrap(), 12);
    assert_eq!(*c3.read().unwrap(), 13);

    drop(s2);
    sink.send(20);
    assert_eq!(*c1.read().unwrap(), 21);
    assert_eq!(*c2.read().unwrap(), 12);
    assert_eq!(*c3.read().unwrap(), 23);
}

#[test]
fn map_n() {
    let sink = Sink::new();
    let s_out = sink
        .stream()
        .map_n(|a, sender| {
            for _ in 0..*a {
                sender.send(*a)
            }
        })
        .collect::<Vec<_>>();

    sink.feed(0..4);

    assert_eq!(s_out.sample(), [1, 2, 2, 3, 3, 3]);
}

#[test]
fn stream_collect() {
    use std::cmp::Ordering;
    use std::collections::*;

    let sink: Sink<i32> = Sink::new();
    let stream = sink.stream();
    let s_vec: Signal<Vec<_>> = stream.collect();
    let s_vecdq: Signal<VecDeque<_>> = stream.collect();
    let s_list: Signal<LinkedList<_>> = stream.collect();
    let s_set: Signal<BTreeSet<_>> = stream.collect();
    let s_string: Signal<String> = stream.map(|v| format!("{} ", v)).collect();

    sink.feed(&[1, 3, -42, 2]);

    assert_eq!(s_vec.sample(), [1, 3, -42, 2]);
    assert_eq!(s_vecdq.sample(), [1, 3, -42, 2]);
    assert_eq!(
        s_list.sample().iter().cmp([1, 3, -42, 2].iter()),
        Ordering::Equal
    );
    assert_eq!(
        s_set.sample().iter().cmp([-42, 1, 2, 3].iter()),
        Ordering::Equal
    );
    assert_eq!(s_string.sample(), "1 3 -42 2 ");

    let sink = Sink::new();
    let s_string: Signal<String> = sink.stream().collect();

    sink.feed("abZc".chars());

    assert_eq!(s_string.sample(), "abZc");
}

#[test]
fn signal_chain() {
    let sink = Sink::new();

    let sig_a = sink.stream().hold(0);
    let sig_b = sig_a.map(move |a| a + 1);
    let sig_c = sig_b.map(|a| a * 2);
    let sig_d = sig_c.map(|a| format!("({})", a));
    let sig_e = sig_d.map(|s| s + ".-");

    assert_eq!(sig_e.sample(), "(2).-");
    assert_eq!(sig_e.sample(), "(2).-");

    sink.send(42);

    assert_eq!(sig_e.sample(), "(86).-");
    assert_eq!(sig_e.sample(), "(86).-");
}

#[test]
fn signal_take() {
    #[derive(Debug, Clone, PartialEq, Eq, Default)]
    struct Value(i32);

    let sink = Sink::new();

    let sig = sink.stream().hold(Value(0)).map(|v| Value(v.0 + 1));

    sink.send(Value(41));

    assert_eq!(sig.clone().take(), Value(42));
    assert_eq!(sig.take(), Value(42));
}

#[test]
fn signal_threading() {
    let sink = Sink::new();
    let sig = sink.stream().hold(0);
    sink.send(2);

    let threads: Vec<_> = (0..6)
        .map(|i| {
            let sig_ = sig.clone();
            std::thread::spawn(move || sig_.map(move |x: i32| x.pow(i)).sample())
        })
        .collect();

    let result: Vec<_> = threads.into_iter().map(|th| th.join().unwrap()).collect();
    assert_eq!(result, [1, 2, 4, 8, 16, 32]);
}

#[test]
fn stream_threading() {
    let sink = Sink::new();
    let sig = sink.stream().map(|x| *x + 1).fold(1, |a, x| a * *x);

    let threads: Vec<_> = (0..6)
        .map(|i| {
            let sink_ = sink.clone();
            std::thread::spawn(move || sink_.send(i))
        })
        .collect();

    for th in threads {
        th.join().unwrap();
    }

    assert_eq!(sig.sample(), 720);
}

#[test]
fn send_non_sync() {
    use std::cell::Cell;

    let sink: Sink<Cell<_>> = Sink::new();
    let sig = sink
        .stream()
        .map(|x| Cell::new(x.get() * 2))
        .hold(Default::default())
        .map(|x| Cell::new(x.get() + 2));

    sink.send(Cell::new(20));

    assert_eq!(sig.sample(), Cell::new(42));
}
<|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 = 0b111111111;
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> BTree<'a, K> {
	fn new<'b>(segment_id: u64, manager: ConcurrentManager) -> BTree<'b, K> {
		let tree_base = buffer::join_segment(segment_id, 1);
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(tree_base),
			next_free_page: 2,
		}
	}

	fn insert(&mut self, key: K, value: schema::TID) {
		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> {
		None
	}
}

/* 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>(&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> 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()) {
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

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

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

		// 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;

		// 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);
		}
	}
}

#[unsafe_destructor]
impl<'a, K> Drop for LeafNode<'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);
	}
}

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

impl<'a, K: TotalOrd + Zero> 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> {
		let mut place = 0;
		// locate the place where to insert
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry i {:?}, key {:?}", self.entries[i], self.entries[i].key);
			// TODO find place
		}
		let go_to_page = self.entries[place].page_id;
		if go_to_page == 0 {
			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, value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			return split_candidate
		}

		// currently not caring about splitting branch pages
		None
	}
}

#[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)));
	bt.insert(42, schema::TID::new(0, 0));
	assert!(false);
}

#[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>Super simple insert and lookup works<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 = 0b111111111;
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> 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) {
		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>(&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> 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()) {
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

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

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

		// 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;

		// 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!("Ohai, unfixing page");
		// 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> 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> {
		let mut place = 0;
		// locate the place where to insert
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry i {:?}, key {:?}", self.entries[i], self.entries[i].key);
			// TODO find place
		}
		let go_to_page = self.entries[place].page_id;
		if go_to_page == 0 {
			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, value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			return split_candidate
		}

		// currently not caring about splitting branch pages
		None
	}

	fn lookup(self, manager: ConcurrentManager, key: &K) -> Option<schema::TID> {
		println!("Doing lookup in branch node");
		let mut next_page = 0;
		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 {:?}, key {:?}", self.entries[i], self.entries[i].key);
			if &self.entries[i].key <= key {
				// found the branch into which to descend
				next_page = self.entries[i].page_id;
				break;
			}
		}
		let ln = LazyNode::new(next_page);
		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);
	println!("Lookup: {}", bt.lookup(&42));

	assert!(false);
}

#[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|>