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

use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::PathBuf};

use crate::{common::ui::UI,
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs}};

use crate::{config,
            error::Result};

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";

const ORIGIN_ENVVAR: &str = "HAB_ORIGIN";
const STUDIO_CMD: &str = "hab-studio";
const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    if henv::var(ORIGIN_ENVVAR).is_err() {
        let config = config::load()?;
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::{default_cache_key_path,
                                 init},
                        env as henv,
                        fs::{am_i_root,
                             find_command},
                        os::process,
                        package::PackageIdent,
                        users::linux as group},
                VERSION};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";

    pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    exec::command_from_min_pkg(ui,
                                               super::STUDIO_CMD,
                                               &ident,
                                               &default_cache_key_path(None),
                                               0)?
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(&args) && has_docker_group()) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::{default_cache_key_path,
                                 init},
                        env as henv,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              path::PathBuf,
              str::FromStr};

    pub fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split("/").collect();
                let ident = PackageIdent::from_str(&format!("{}/{}",
                                                            super::STUDIO_PACKAGE_IDENT,
                                                            version[0]))?;
                exec::command_from_min_pkg(ui,
                                           super::STUDIO_CMD,
                                           &ident,
                                           &default_cache_key_path(None),
                                           0)?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == String::from("-D") {
                return false;
            }
        }

        // -w/--windows is deprecated and should be removed in a post 0.64.0 release
        for arg in args.iter() {
            let str_arg = arg.to_string_lossy().to_lowercase();
            if str_arg == String::from("--windows") || str_arg == String::from("-w") {
                return true;
            }
        }

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

use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::PathBuf};

use crate::{common::ui::UI,
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs}};

use crate::{config,
            error::Result};

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";

const ORIGIN_ENVVAR: &str = "HAB_ORIGIN";
const STUDIO_CMD: &str = "hab-studio";
const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    if henv::var(ORIGIN_ENVVAR).is_err() {
        let config = config::load()?;
        if let Some(default_origin) = config.origin {
            debug!("Setting default origin {} via CLI config", &default_origin);
            env::set_var("HAB_ORIGIN", default_origin);
        }
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::{default_cache_key_path,
                                 init},
                        env as henv,
                        fs::{am_i_root,
                             find_command},
                        os::process,
                        package::PackageIdent,
                        users::linux as group},
                VERSION};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";

    pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    exec::command_from_min_pkg(ui,
                                               super::STUDIO_CMD,
                                               &ident,
                                               &default_cache_key_path(None),
                                               0)?
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::{default_cache_key_path,
                                 init},
                        env as henv,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              path::PathBuf,
              str::FromStr};

    pub fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split("/").collect();
                let ident = PackageIdent::from_str(&format!("{}/{}",
                                                            super::STUDIO_PACKAGE_IDENT,
                                                            version[0]))?;
                exec::command_from_min_pkg(ui,
                                           super::STUDIO_CMD,
                                           &ident,
                                           &default_cache_key_path(None),
                                           0)?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == String::from("-D") {
                return false;
            }
        }

        // -w/--windows is deprecated and should be removed in a post 0.64.0 release
        for arg in args.iter() {
            let str_arg = arg.to_string_lossy().to_lowercase();
            if str_arg == String::from("--windows") || str_arg == String::from("-w") {
                return true;
            }
        }

        return true;
    }
}
<|endoftext|>


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

use std::error::Error as StdError;
use std::fmt;
use std::borrow::Cow;

use super::Offset;

#[derive(Debug)]
/// This structure represent `encoding` specific errors.
/// This errors returned by function `check` of each `Field`.
pub enum Error {
    // TODO: Check this message after refactor buffer (ECR-156).
    /// Payload is short for this message.
    UnexpectedlyShortPayload {
        /// real message size
        actual_size: Offset,
        /// expected size of fixed part
        minimum_size: Offset,
    },
    /// Boolean value is incorrect
    IncorrectBoolean {
        /// position in buffer where error appears.
        position: Offset,
        /// value that was parsed as bool
        value: u8,
    },
    /// Unsupported floating point value (Infinity, NaN or signaling NaN).
    UnsupportedFloat {
        /// Position in buffer where error appears.
        position: Offset,
        /// Value represented as `f64`.
        value: f64,
    },
    /// SocketAddr header is neither 0 nor 1.
    IncorrectSocketAddrHeader {
        /// Position in buffer where error appears.
        position: Offset,
        /// Header value.
        value: u8,
    },
    /// SocketAddr padding for IPv4 addresses must be 12 bytes of 0s.
    IncorrectSocketAddrPadding {
        /// Position in buffer where error appears.
        position: Offset,
        /// Padding value.
        value: [u8; 12],
    },
    /// Segment reference is incorrect
    IncorrectSegmentReference {
        /// position in buffer where error appears.
        position: Offset,
        /// value that was parsed as segment reference
        value: Offset,
    },
    /// Segment size is incorrect
    IncorrectSegmentSize {
        /// position in buffer where error appears.
        position: Offset,
        /// value that was parsed as size
        value: Offset,
    },
    /// `RawMessage` is to short
    UnexpectedlyShortRawMessage {
        /// position in buffer where error appears.
        position: Offset,
        /// size of raw message in buffer
        size: Offset,
    },
    /// Incorrect size of `RawMessage` found in buffer
    IncorrectSizeOfRawMessage {
        /// position in buffer where error appears.
        position: Offset,
        /// parsed message size
        actual_size: Offset,
        /// expected fixed part message size
        declared_size: Offset,
    },
    /// Incorrect `message_id` found in buffer.
    IncorrectMessageType {
        /// expected `message_id`
        message_type: u16,
    },
    /// Incorrect `service_id` found in buffer.
    IncorrectServiceId {
        /// expected `service_id`
        service_id: u16,
    },
    /// Unsupported message version.
    UnsupportedProtocolVersion {
        /// Actual message version.
        version: u8,
    },
    /// Different segments overlaps
    OverlappingSegment {
        /// last segment ended position
        last_end: Offset,
        /// start of new segment
        start: Offset,
    },
    /// Spaces found between segments
    SpaceBetweenSegments {
        /// last segment ended position
        last_end: Offset,
        /// start of new segment
        start: Offset,
    },
    /// Error in parsing `Utf8` `String`
    Utf8 {
        /// position in buffer where error appears.
        position: Offset,
        /// what error exact was
        error: ::std::str::Utf8Error,
    },
    /// Overflow in Offsets
    OffsetOverflow,
    /// Overflow in Duration.
    DurationOverflow,
    /// Incorrect duration representation.
    IncorrectDuration {
        /// Seconds in gotten duration.
        secs: i64,
        /// Nanoseconds in gotten duration.
        nanos: i32,
    },
    /// Basic error support, for custom fields.
    Basic(Cow<'static, str>),
    /// Other error for custom fields
    Other(Box<StdError>),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} = {:?}", self.description(), self)
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::UnexpectedlyShortPayload { .. } => "Unexpectedly short payload",
            Error::IncorrectBoolean { .. } => "Incorrect boolean value",
            Error::UnsupportedFloat { .. } => "Unsupported float value",
            Error::IncorrectSocketAddrHeader { .. } => "Incorrect SocketAddr header value",
            Error::IncorrectSocketAddrPadding { .. } => "Incorrect SocketAddr padding",
            Error::IncorrectSegmentReference { .. } => "Incorrect segment reference",
            Error::IncorrectSegmentSize { .. } => "Incorrect segment size",
            Error::UnexpectedlyShortRawMessage { .. } => "Unexpectedly short RawMessage",
            Error::IncorrectSizeOfRawMessage { .. } => "Incorrect size of RawMessage",
            Error::IncorrectMessageType { .. } => "Incorrect message type",
            Error::IncorrectServiceId { .. } => "Incorrect service id",
            Error::UnsupportedProtocolVersion { .. } => "Unsupported protocol version",
            Error::OverlappingSegment { .. } => "Overlapping segments",
            Error::SpaceBetweenSegments { .. } => "Space between segments",
            Error::Utf8 { .. } => "Utf8 error in parsing string",
            Error::OffsetOverflow => "Offset pointers overflow",
            Error::DurationOverflow => "Overflow in Duration object",
            Error::IncorrectDuration { .. } => "Incorrect Duration object representation",
            Error::Basic(ref x) => x.as_ref(),
            Error::Other(_) => "Other error",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use std::ops::Deref;
        if let Error::Other(ref error) = *self {
            Some(error.deref())
        } else {
            None
        }
    }
}

impl From<Box<StdError>> for Error {
    fn from(t: Box<StdError>) -> Error {
        Error::Other(t)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(t: Cow<'static, str>) -> Error {
        Error::Basic(t)
    }
}

impl From<&'static str> for Error {
    fn from(t: &'static str) -> Error {
        Error::Basic(t.into())
    }
}
<commit_msg>Fixed doc typo (#665)<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error as StdError;
use std::fmt;
use std::borrow::Cow;

use super::Offset;

#[derive(Debug)]
/// This structure represent `encoding` specific errors.
/// This errors returned by function `check` of each `Field`.
pub enum Error {
    // TODO: Check this message after refactor buffer (ECR-156).
    /// Payload is short for this message.
    UnexpectedlyShortPayload {
        /// real message size.
        actual_size: Offset,
        /// expected size of fixed part.
        minimum_size: Offset,
    },
    /// Boolean value is incorrect.
    IncorrectBoolean {
        /// position in buffer where error appears.
        position: Offset,
        /// value that was parsed as bool.
        value: u8,
    },
    /// Unsupported floating point value (Infinity, NaN or signaling NaN).
    UnsupportedFloat {
        /// Position in buffer where error appears.
        position: Offset,
        /// Value represented as `f64`.
        value: f64,
    },
    /// SocketAddr header is neither 0 nor 1.
    IncorrectSocketAddrHeader {
        /// Position in buffer where error appears.
        position: Offset,
        /// Header value.
        value: u8,
    },
    /// SocketAddr padding for IPv4 addresses must be 12 bytes of 0s.
    IncorrectSocketAddrPadding {
        /// Position in buffer where error appears.
        position: Offset,
        /// Padding value.
        value: [u8; 12],
    },
    /// Segment reference is incorrect.
    IncorrectSegmentReference {
        /// position in buffer where error appears.
        position: Offset,
        /// value that was parsed as segment reference.
        value: Offset,
    },
    /// Segment size is incorrect.
    IncorrectSegmentSize {
        /// position in buffer where error appears.
        position: Offset,
        /// value that was parsed as size.
        value: Offset,
    },
    /// `RawMessage` is too short
    UnexpectedlyShortRawMessage {
        /// position in buffer where error appears.
        position: Offset,
        /// size of raw message in buffer.
        size: Offset,
    },
    /// Incorrect size of `RawMessage` found in buffer.
    IncorrectSizeOfRawMessage {
        /// position in buffer where error appears.
        position: Offset,
        /// parsed message size.
        actual_size: Offset,
        /// expected fixed part message size.
        declared_size: Offset,
    },
    /// Incorrect `message_id` found in buffer.
    IncorrectMessageType {
        /// expected `message_id`
        message_type: u16,
    },
    /// Incorrect `service_id` found in buffer.
    IncorrectServiceId {
        /// expected `service_id`.
        service_id: u16,
    },
    /// Unsupported message version.
    UnsupportedProtocolVersion {
        /// Actual message version.
        version: u8,
    },
    /// Different segments overlaps.
    OverlappingSegment {
        /// last segment ended position.
        last_end: Offset,
        /// start of new segment.
        start: Offset,
    },
    /// Spaces found between segments.
    SpaceBetweenSegments {
        /// last segment ended position.
        last_end: Offset,
        /// start of new segment.
        start: Offset,
    },
    /// Error in parsing `Utf8` `String`.
    Utf8 {
        /// position in buffer where error appears.
        position: Offset,
        /// what error exact was.
        error: ::std::str::Utf8Error,
    },
    /// Overflow in Offsets.
    OffsetOverflow,
    /// Overflow in Duration.
    DurationOverflow,
    /// Incorrect duration representation.
    IncorrectDuration {
        /// Seconds in gotten duration.
        secs: i64,
        /// Nanoseconds in gotten duration.
        nanos: i32,
    },
    /// Basic error support, for custom fields.
    Basic(Cow<'static, str>),
    /// Other error for custom fields.
    Other(Box<StdError>),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} = {:?}", self.description(), self)
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::UnexpectedlyShortPayload { .. } => "Unexpectedly short payload",
            Error::IncorrectBoolean { .. } => "Incorrect boolean value",
            Error::UnsupportedFloat { .. } => "Unsupported float value",
            Error::IncorrectSocketAddrHeader { .. } => "Incorrect SocketAddr header value",
            Error::IncorrectSocketAddrPadding { .. } => "Incorrect SocketAddr padding",
            Error::IncorrectSegmentReference { .. } => "Incorrect segment reference",
            Error::IncorrectSegmentSize { .. } => "Incorrect segment size",
            Error::UnexpectedlyShortRawMessage { .. } => "Unexpectedly short RawMessage",
            Error::IncorrectSizeOfRawMessage { .. } => "Incorrect size of RawMessage",
            Error::IncorrectMessageType { .. } => "Incorrect message type",
            Error::IncorrectServiceId { .. } => "Incorrect service id",
            Error::UnsupportedProtocolVersion { .. } => "Unsupported protocol version",
            Error::OverlappingSegment { .. } => "Overlapping segments",
            Error::SpaceBetweenSegments { .. } => "Space between segments",
            Error::Utf8 { .. } => "Utf8 error in parsing string",
            Error::OffsetOverflow => "Offset pointers overflow",
            Error::DurationOverflow => "Overflow in Duration object",
            Error::IncorrectDuration { .. } => "Incorrect Duration object representation",
            Error::Basic(ref x) => x.as_ref(),
            Error::Other(_) => "Other error",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use std::ops::Deref;
        if let Error::Other(ref error) = *self {
            Some(error.deref())
        } else {
            None
        }
    }
}

impl From<Box<StdError>> for Error {
    fn from(t: Box<StdError>) -> Error {
        Error::Other(t)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(t: Cow<'static, str>) -> Error {
        Error::Basic(t)
    }
}

impl From<&'static str> for Error {
    fn from(t: &'static str) -> Error {
        Error::Basic(t.into())
    }
}
<|endoftext|>


<commit_before>
use std::str;
use inlined_parser::{Node, Children, Data};
use self::unescape::unescapeString;

#[macro_escape]
mod macros;
mod unescape;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~" )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Suffix" => suffixOutput( node ),
    "Prefix" => prefixOutput( node ),
    "Primary" => primaryOutput( node ),
    "DOT" => ~"base::Dot",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn wrapNodeOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNode( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() > 1 {
    wrapChildrenOutput( ~"or!( ", node , ~" )" )
  } else {
    codeForNodeContents( node )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() > 1 {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNode( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  } else {
    codeForNodeContents( node )
  }
}

fn suffixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 2 {
    let macro_name = match children.get( 1 ).name {
      "QUESTION" => ~"opt",
      "STAR" => ~"star",
      "PLUS" => ~"plus",
      _ => fail!( "Bad second child." )
    };

    [ macro_name, ~"!( ", codeForNode( children.get( 0 ) ), ~" )" ].concat()
  } else {
    codeForNodeContents( node )
  }
}

fn prefixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 2 {
    let macro_name = children.get( 0 ).name.chars()
      .map( |x| x.to_lowercase() ).collect();
    [ macro_name, ~"!( ", codeForNode( children.get( 1 ) ), ~" )" ].concat()
  } else {
    codeForNodeContents( node )
  }
}

fn primaryOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 && children.get( 0 ).name == "Identifier" {
    wrapNodeOutput( ~"ex!( ", children.get( 0 ), ~" )" )
  } else {
    codeForNodeContents( node )
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
    .replace( r"\\]", r"]" )
    .replace( r"\\[", r"[" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  let full = codeForNodeContents( node );
  // TODO: write escape func
  let content = unescapeString( full.slice_chars( 1, full.len() - 1 ) )
    .replace( r"\", r"\\" )
    .replace( "\n", r"\n" )
    .replace( "\t", r"\t" )
    .replace( "\r", r"\r" )
    .replace( "\"", r#"\""# );
  format!( "{}!( \"{}\" )", rule_name, content )
}
<commit_msg>More refactoring<commit_after>
use std::str;
use inlined_parser::{Node, Children, Data};
use self::unescape::unescapeString;

#[macro_escape]
mod macros;
mod unescape;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( "rule!( ", node, " )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Suffix" => suffixOutput( node ),
    "Prefix" => prefixOutput( node ),
    "Primary" => primaryOutput( node ),
    "DOT" => ~"base::Dot",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: &str, node: &Node, after: &str ) -> ~str {
  [ before.into_maybe_owned(),
    codeForNodeContents( node ).into_maybe_owned(),
    after.into_maybe_owned() ].concat()
}

fn wrapNodeOutput( before: &str, node: &Node, after: &str ) -> ~str {
  [ before.into_maybe_owned(),
    codeForNode( node ).into_maybe_owned(),
    after.into_maybe_owned() ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() > 1 {
    wrapChildrenOutput( "or!( ", node , " )" )
  } else {
    codeForNodeContents( node )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() > 1 {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNode( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  } else {
    codeForNodeContents( node )
  }
}

fn suffixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 2 {
    let macro_name = match children.get( 1 ).name {
      "QUESTION" => ~"opt",
      "STAR" => ~"star",
      "PLUS" => ~"plus",
      _ => fail!( "Bad second child." )
    };

    [ macro_name, ~"!( ", codeForNode( children.get( 0 ) ), ~" )" ].concat()
  } else {
    codeForNodeContents( node )
  }
}

fn prefixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 2 {
    let macro_name = children.get( 0 ).name.chars()
      .map( |x| x.to_lowercase() ).collect();
    [ macro_name, ~"!( ", codeForNode( children.get( 1 ) ), ~" )" ].concat()
  } else {
    codeForNodeContents( node )
  }
}

fn primaryOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 && children.get( 0 ).name == "Identifier" {
    wrapNodeOutput( "ex!( ", children.get( 0 ), " )" )
  } else {
    codeForNodeContents( node )
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
    .replace( r"\\]", r"]" )
    .replace( r"\\[", r"[" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  let full = codeForNodeContents( node );
  // TODO: write escape func
  let content = unescapeString( full.slice_chars( 1, full.len() - 1 ) )
    .replace( r"\", r"\\" )
    .replace( "\n", r"\n" )
    .replace( "\t", r"\t" )
    .replace( "\r", r"\r" )
    .replace( "\"", r#"\""# );
  format!( "{}!( \"{}\" )", rule_name, content )
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::Future;

/// Compute the frequency of each letter (technically of each unicode codepoint) using the given
/// number of worker threads.
pub fn frequency(texts: &[&str], num_workers: usize) -> HashMap<char, usize> {
    assert!(num_workers > 0);
    let part_size_floor = texts.len() / num_workers;
    let rem = texts.len() % num_workers;
    let part_size = if rem > 0 { part_size_floor + 1 } else { part_size_floor };
    let mut parts: Vec<Vec<String>> = Vec::with_capacity(part_size);
    for _ in 0 .. num_workers {
        parts.push(Vec::with_capacity(part_size));
    }
    let mut i = 0;
    for line in texts.iter() {
        // We'll need to clone those strings in order to satisfy some lifetime guarantees. Basically
        // it's hard for the system to be sure that the threads spawned don't outlive the strings.
        parts[i].push(line.to_string());
        i = (i + 1) % num_workers;
    }
    let futures = parts.into_iter().map(|part| Future::spawn(move || { count(part) }));
    let mut results: HashMap<char, usize> = HashMap::new();
    for mut fut in futures {
        let part_results = fut.get();
        for (c, n) in part_results.into_iter() {
            match results.entry(c) {
                Entry::Vacant(view) => { view.insert(n); },
                Entry::Occupied(mut view) => {
                    *view.get_mut() += n;
                }
            }
        }
    }
    results
}

fn count(lines: Vec<String>) -> HashMap<char, usize> {
    let mut results: HashMap<char, usize> = HashMap::new();
    for line in lines.iter() {
        for c in line.chars() {
            if c.is_alphabetic() {
                match results.entry(c.to_ascii_lowercase()) {
                    Entry::Vacant(view) => { view.insert(1); },
                    Entry::Occupied(mut view) => {
                        *view.get_mut() += 1;
                    }
                }
            }
        }
    }
    results
}
<commit_msg>Change to a unicode method<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::Future;

/// Compute the frequency of each letter (technically of each unicode codepoint) using the given
/// number of worker threads.
pub fn frequency(texts: &[&str], num_workers: usize) -> HashMap<char, usize> {
    assert!(num_workers > 0);
    let part_size_floor = texts.len() / num_workers;
    let rem = texts.len() % num_workers;
    let part_size = if rem > 0 { part_size_floor + 1 } else { part_size_floor };
    let mut parts: Vec<Vec<String>> = Vec::with_capacity(part_size);
    for _ in 0 .. num_workers {
        parts.push(Vec::with_capacity(part_size));
    }
    let mut i = 0;
    for line in texts.iter() {
        // We'll need to clone those strings in order to satisfy some lifetime guarantees. Basically
        // it's hard for the system to be sure that the threads spawned don't outlive the strings.
        parts[i].push(line.to_string());
        i = (i + 1) % num_workers;
    }
    let futures = parts.into_iter().map(|part| Future::spawn(move || { count(part) }));
    let mut results: HashMap<char, usize> = HashMap::new();
    for mut fut in futures {
        let part_results = fut.get();
        for (c, n) in part_results.into_iter() {
            match results.entry(c) {
                Entry::Vacant(view) => { view.insert(n); },
                Entry::Occupied(mut view) => {
                    *view.get_mut() += n;
                }
            }
        }
    }
    results
}

fn count(lines: Vec<String>) -> HashMap<char, usize> {
    let mut results: HashMap<char, usize> = HashMap::new();
    for line in lines.iter() {
        for c in line.chars() {
            if c.is_alphabetic() {
                match results.entry(c.to_lowercase().next().unwrap()) {
                    Entry::Vacant(view) => { view.insert(1); },
                    Entry::Occupied(mut view) => {
                        *view.get_mut() += 1;
                    }
                }
            }
        }
    }
    results
}
<|endoftext|>


<commit_before>//! Error types

pub use default_connector::Error as TlsError;
pub use hyper::Error as HyperError;

use std::error::Error as StdError;
use std::fmt::{self, Display, Formatter};
use std::str::Utf8Error;
use types::StatusCode;

/// An error occurred while trying to connect to a Stream.
#[derive(Debug)]
pub enum Error {
    /// An HTTP error from the Stream.
    Http(StatusCode),
    /// An error from the `hyper` crate.
    Hyper(HyperError),
    TimedOut,
    Tls(TlsError),
    Utf8(Utf8Error),
    Custom(Box<StdError + Send + Sync>),
}

impl Error {
    pub fn custom<E>(error: E) -> Self where Box<StdError + Send + Sync>: From<E> {
        Error::Custom(From::from(error))
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        use Error::*;

        match *self {
            Http(ref status) => status.canonical_reason().unwrap_or("<unknown status code>"),
            Hyper(ref e) => e.description(),
            TimedOut => "timed out",
            Tls(ref e) => e.description(),
            Utf8(ref e) => e.description(),
            Custom(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        use Error::*;

        match *self {
            Hyper(ref e) => Some(e),
            Utf8(ref e) => Some(e),
            Custom(ref e) => Some(e.as_ref()),
            Tls(ref e) => Some(e),
            Http(_) | TimedOut => None,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use Error::*;

        match *self {
            Http(ref code) => Display::fmt(code, f),
            Hyper(ref e) => Display::fmt(e, f),
            TimedOut => Display::fmt(self.description(), f),
            Tls(ref e) => Display::fmt(e, f),
            Utf8(ref e) => Display::fmt(e, f),
            Custom(ref e) => Display::fmt(e, f),
        }
    }
}
<commit_msg>Update documentation<commit_after>//! Error types

pub use default_connector::Error as TlsError;
pub use hyper::Error as HyperError;

use std::error::{self, Error as _Error};
use std::fmt::{self, Display, Formatter};
use std::str::Utf8Error;
use types::StatusCode;

/// An error occurred while trying to connect to a Stream.
#[derive(Debug)]
pub enum Error {
    /// An HTTP error from the Stream.
    Http(StatusCode),
    /// An error from the `hyper` crate.
    Hyper(HyperError),
    /// The stream has timed out.
    TimedOut,
    /// An error occured when initializing a TLS client.
    Tls(TlsError),
    /// Twitter returned a non-UTF-8 string.
    Utf8(Utf8Error),
    /// User-defined error.
    Custom(Box<error::Error + Send + Sync>),
}

impl Error {
    pub fn custom<E>(error: E) -> Self where Box<error::Error + Send + Sync>: From<E> {
        Error::Custom(From::from(error))
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use Error::*;

        match *self {
            Http(ref status) => status.canonical_reason().unwrap_or("<unknown status code>"),
            Hyper(ref e) => e.description(),
            TimedOut => "timed out",
            Tls(ref e) => e.description(),
            Utf8(ref e) => e.description(),
            Custom(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        use Error::*;

        match *self {
            Hyper(ref e) => Some(e),
            Utf8(ref e) => Some(e),
            Custom(ref e) => Some(e.as_ref()),
            Tls(ref e) => Some(e),
            Http(_) | TimedOut => None,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use Error::*;

        match *self {
            Http(ref code) => Display::fmt(code, f),
            Hyper(ref e) => Display::fmt(e, f),
            TimedOut => Display::fmt(self.description(), f),
            Tls(ref e) => Display::fmt(e, f),
            Utf8(ref e) => Display::fmt(e, f),
            Custom(ref e) => Display::fmt(e, f),
        }
    }
}
<|endoftext|>


<commit_before>//! The [loca (Index to Location)][loca] table
//!
//! [loca]: https://docs.microsoft.com/en-us/typography/opentype/spec/loca

use font_types::{BigEndian, Offset32, Tag};
use zerocopy::LayoutVerified;

/// 'loca'
pub const TAG: Tag = Tag::new(b"loca");

/// The [loca] table.
///
/// [loca]: https://docs.microsoft.com/en-us/typography/opentype/spec/loca
pub enum Loca<'a> {
    Short(&'a [BigEndian<u16>]),
    Long(&'a [BigEndian<Offset32>]),
}

impl<'a> Loca<'a> {
    /// Create a new loca table.
    ///
    /// num_glyphs should be read from [maxp], and is_short from [head].
    ///
    /// [maxp]: super::Maxp
    /// [head]: super::head::Head
    pub fn read(data: &'a [u8], num_glyphs: u16, is_long: bool) -> Option<Self> {
        let num_glyphs = num_glyphs as usize;
        if is_long {
            let (data, _) = LayoutVerified::new_slice_unaligned_from_prefix(data, num_glyphs + 1)?;
            Some(Loca::Long(data.into_slice()))
        } else {
            let (data, _) = LayoutVerified::new_slice_unaligned_from_prefix(data, num_glyphs + 1)?;
            Some(Loca::Short(data.into_slice()))
        }
    }

    /// Attempt to return the offset for a given glyph id.
    pub fn get(&self, idx: usize) -> Option<Offset32> {
        match self {
            Loca::Short(data) => {
                let value = data.get(idx)?.get();
                Some(Offset32::new(value as u32 * 2))
            }

            Loca::Long(data) => data.get(idx).copied().map(BigEndian::get),
        }
    }

    /// Iterate all offsets
    pub fn iter(&self) -> impl Iterator<Item = Offset32> + '_ {
        let mut idx = 0;
        std::iter::from_fn(move || {
            let result = self.get(idx);
            idx += 1;
            result
        })
    }
}
<commit_msg>Remove misplaced file<commit_after><|endoftext|>


<commit_before>use std;
use std::ops::Range;
use std::collections::HashSet;

use rand;
use rand::Rng;

use tcod;
use tcod::console::Console;
use tcod::Color;
use tcod::colors;

use traits::{Position, Renderable};
use units::Unit;

use point::Point;
use rectangle::Rectangle;

use SCREEN_WIDTH;
use SCREEN_HEIGHT;

const MAP_MIN_WIDTH: u8 = SCREEN_WIDTH;
const MAP_MIN_HEIGHT: u8 = SCREEN_HEIGHT;
pub const MAP_MAX_WIDTH: u8 = std::u8::MAX;
pub const MAP_MAX_HEIGHT: u8 = std::u8::MAX;

const ROOM_MAX_SIZE: u8 = 10;
const ROOM_MIN_SIZE: u8 = 6;
// This value determines the maximum number of rooms for a given map size.
// This was calculated by the previous map size (80 x 45) divided by the
// previous max room count of 30.
// This should provide a similar room densiter for each map.
const ROOM_PER_TILE: u8 = 120;

const ERR_MSG_TUNNEL: &str = "Failed to create tunnel.";
const ERR_MSG_ROOM: &str = "Failed to create room.";
const ERR_MSG_ROOM_CMP: &str = "Error comparing rooms.";

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TileType {
    Floor,
    Wall,
}

impl TileType {
    fn get_color_not_visible(self) -> Color {
        match self {
            TileType::Floor => Color::new(50, 50, 150),
            TileType::Wall => Color::new(0, 0, 100),
        }
    }

    fn get_color_visible(self) -> Color {
        match self {
            TileType::Floor => Color::new(200, 180, 50),
            TileType::Wall => Color::new(130, 110, 50),
        }
    }

    fn get_glyph(self) -> char {
        match self {
            TileType::Floor => '.',
            TileType::Wall => '#',
        }
    }

    pub fn blocks_move(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }

    pub fn blocks_sight(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }
}

#[derive(Debug)]
pub struct Tile {
    position: Point<i16>,
    tile_type: TileType,
    is_explored: bool,
    is_visible: bool,
}

impl Position for Tile {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl Renderable for Tile {
    fn get_color(&self) -> Color {
        if !self.is_explored {
            tcod::colors::BLACK
        } else {
            match self.is_visible {
                true => self.tile_type.get_color_visible(),
                false => self.tile_type.get_color_not_visible(),
            }
        }
    }
    fn get_glyph(&self) -> char {
        self.tile_type.get_glyph()
    }
}

impl Tile {
    pub fn new(pos: Point<i16>, tile_type: TileType) -> Tile {
        Tile{
            position: pos,
            tile_type: tile_type,
            is_explored: false,
            is_visible: false,
        }
    }
}

pub struct Map {
    width: u8,
    height: u8,
    tile_map: Vec<Tile>,
    fov_map: tcod::map::Map,
    npcs: Vec<Unit>,
}

impl Map {
    pub fn init() -> (Map, Point<i16>) {
        let mut rng = rand::thread_rng();

        let map_width = rng.gen_range(MAP_MIN_WIDTH, MAP_MAX_WIDTH);
        let map_height = rng.gen_range(MAP_MIN_HEIGHT, MAP_MAX_HEIGHT);

        let mut map = vec![];
        for y in 0..map_height {
            for x in 0..map_width {
                map.push( Tile::new(Point{x: x as i16, y: y as i16}, TileType::Wall) );
            }
        }

        let mut map = Map {
            width: map_width,
            height: map_height,
            tile_map: map,
            fov_map: tcod::map::Map::new(map_width as i32, map_height as i32),
            npcs: vec![],
        };

        // Set all tiles to be not walkable, not transparent.
        // We'll be setting these in the build_rooms and build_coridoors methods.
        map.fov_map.clear(false, false);

        let (rooms, player_start) = map.build_rooms(&mut rng);
        map.build_coridoors(&rooms, &mut rng);

        (map, player_start)
    }

    fn build_rooms(&mut self, rng: &mut rand::ThreadRng) -> (Vec<Rectangle>, Point<i16>) {
        let mut rooms = vec![];
        let mut player_start = Point{x:0, y:0};

        // Casts are to avoid overflow.
        let max_rooms = self.width as u16 * self.height as u16 / ROOM_PER_TILE as u16;

        for _ in 0..max_rooms {
            let width = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);
            let height = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);

            let room = Rectangle::new(
                Point {
                    x: rng.gen_range(0, self.width as i16 - width as i16 - 1),
                    y: rng.gen_range(0, self.height as i16 - height as i16 - 1)
                },
                (width, height)
            );

            if !rooms.iter().any(|r: &Rectangle| r.is_intersecting(&room)) {
                self.create_room(&room).expect(ERR_MSG_ROOM);

                if rooms.len() == 0 {
                    player_start = room.centre();
                }

                rooms.push(room);
            }
        }

        (rooms, player_start)
    }

    fn build_coridoors(&mut self, rooms: &Vec<Rectangle>, rng: &mut rand::ThreadRng) {
        let mut sorted_rooms: Vec<_> = rooms.iter().map(|r| r).collect();
        let mut connected_rooms = HashSet::new();

        for room in rooms {
            sorted_rooms.sort_by(|a,b| (room.centre() - a.centre()).sqr_radius().partial_cmp(&(room.centre() - b.centre()).sqr_radius()).expect(ERR_MSG_ROOM_CMP) );

            for next in sorted_rooms.iter().skip(1).take(3) {
                if connected_rooms.contains(&(*next, room)) {
                    continue;
                }

                connected_rooms.insert((room, *next));

                let r1_centre = room.centre();
                let r2_centre = next.centre();

                // Decide whether to first tunnel horizontally or vertically.
                if rng.gen_weighted_bool(2) {
                    // Horizontal
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r1_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_v_tunnel(r2_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                } else {
                    // Vertical
                    self.create_v_tunnel(r1_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r2_centre.y).expect(ERR_MSG_TUNNEL);
                }
            }
        }
    }

    pub fn render_map<T: Console>(&self, cons: &mut T) {
        for tile in self.tile_map.iter() {
            tile.render(cons);
        }
    }

    pub fn render_npcs<T: Console>(&self, cons: &mut T) {
        for unit in self.npcs.iter() {
            if self.fov_map.is_in_fov(unit.get_x() as i32, unit.get_y() as i32) {
                unit.render(cons);
            }
        }
    }

    pub fn point_in_map(&self, Point{x,y}: Point<i16>) -> bool {
        x >= 0 && x < self.width as i16 && y >= 0 && y < self.height as i16
    }

    pub fn get_tile_type(&self, pos: Point<i16>) -> Result<TileType,()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x, y} = pos;
            Ok(self.tile_map[y as usize * self.width as usize + x as usize].tile_type)
        }
    }

    pub fn update_fov(&mut self, Point{x, y}: Point<i16>, light_radius: u8) {
        self.fov_map.compute_fov(x as i32, y as i32, light_radius as i32, true, tcod::map::FovAlgorithm::Permissive0);

        // I've opted to update the tile map here, because it doesn't make sense that
        // a function for rendering should need to mutate the object.
        // It does make this function more expensive to run, but it won't be run
        // too frequently.
        for tile in self.tile_map.iter_mut() {
            tile.is_visible = self.fov_map.is_in_fov(tile.get_x() as i32, tile.get_y() as i32);

            if tile.is_visible {
                tile.is_explored = true;
            }
        }
    }

    pub fn get_map_size(&self) -> (u8, u8) {
        (self.width, self.height)
    }

    fn create_v_tunnel(&mut self, x: i16, y_r: Range<i16>) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let y_r = if y_r.start > y_r.end {
            y_r.end+1 .. y_r.start+1
        } else {
            y_r
        };

        for y in y_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
            self.fov_map.set(x as i32, y as i32, true, true);
        }

        Ok(())
    }

    fn create_h_tunnel(&mut self, x_r: Range<i16>, y: i16) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let x_r = if x_r.start > x_r.end {
            x_r.end+1 .. x_r.start+1
        } else {
            x_r
        };

        for x in x_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
            self.fov_map.set(x as i32, y as i32, true, true);
        }

        Ok(())
    }

    fn create_room(&mut self, rect: &Rectangle) -> Result<(),()> {
        for y in (rect.top_left.y+1)..rect.bottom_right.y {
            for x in (rect.top_left.x+1)..rect.bottom_right.x {
                let pos = Point{x:x, y:y};
                self.set_tile_type(pos, TileType::Floor)?;
                self.fov_map.set(x as i32, y as i32, true, true);
            }
        }

        Ok(())
    }

    fn set_tile_type(&mut self, pos: Point<i16>, new_tile: TileType) -> Result<(),()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x,y} = pos;
            self.tile_map[y as usize * self.width as usize + x as usize].tile_type = new_tile;

            Ok(())
        }
    }
}<commit_msg>Removed unused import.<commit_after>use std;
use std::ops::Range;
use std::collections::HashSet;

use rand;
use rand::Rng;

use tcod;
use tcod::console::Console;
use tcod::Color;

use traits::{Position, Renderable};
use units::Unit;

use point::Point;
use rectangle::Rectangle;

use SCREEN_WIDTH;
use SCREEN_HEIGHT;

const MAP_MIN_WIDTH: u8 = SCREEN_WIDTH;
const MAP_MIN_HEIGHT: u8 = SCREEN_HEIGHT;
pub const MAP_MAX_WIDTH: u8 = std::u8::MAX;
pub const MAP_MAX_HEIGHT: u8 = std::u8::MAX;

const ROOM_MAX_SIZE: u8 = 10;
const ROOM_MIN_SIZE: u8 = 6;
// This value determines the maximum number of rooms for a given map size.
// This was calculated by the previous map size (80 x 45) divided by the
// previous max room count of 30.
// This should provide a similar room densiter for each map.
const ROOM_PER_TILE: u8 = 120;

const ERR_MSG_TUNNEL: &str = "Failed to create tunnel.";
const ERR_MSG_ROOM: &str = "Failed to create room.";
const ERR_MSG_ROOM_CMP: &str = "Error comparing rooms.";

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TileType {
    Floor,
    Wall,
}

impl TileType {
    fn get_color_not_visible(self) -> Color {
        match self {
            TileType::Floor => Color::new(50, 50, 150),
            TileType::Wall => Color::new(0, 0, 100),
        }
    }

    fn get_color_visible(self) -> Color {
        match self {
            TileType::Floor => Color::new(200, 180, 50),
            TileType::Wall => Color::new(130, 110, 50),
        }
    }

    fn get_glyph(self) -> char {
        match self {
            TileType::Floor => '.',
            TileType::Wall => '#',
        }
    }

    pub fn blocks_move(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }

    pub fn blocks_sight(self) -> bool {
        match self {
            TileType::Floor => false,
            TileType::Wall => true,
        }
    }
}

#[derive(Debug)]
pub struct Tile {
    position: Point<i16>,
    tile_type: TileType,
    is_explored: bool,
    is_visible: bool,
}

impl Position for Tile {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl Renderable for Tile {
    fn get_color(&self) -> Color {
        if !self.is_explored {
            tcod::colors::BLACK
        } else {
            match self.is_visible {
                true => self.tile_type.get_color_visible(),
                false => self.tile_type.get_color_not_visible(),
            }
        }
    }
    fn get_glyph(&self) -> char {
        self.tile_type.get_glyph()
    }
}

impl Tile {
    pub fn new(pos: Point<i16>, tile_type: TileType) -> Tile {
        Tile{
            position: pos,
            tile_type: tile_type,
            is_explored: false,
            is_visible: false,
        }
    }
}

pub struct Map {
    width: u8,
    height: u8,
    tile_map: Vec<Tile>,
    fov_map: tcod::map::Map,
    npcs: Vec<Unit>,
}

impl Map {
    pub fn init() -> (Map, Point<i16>) {
        let mut rng = rand::thread_rng();

        let map_width = rng.gen_range(MAP_MIN_WIDTH, MAP_MAX_WIDTH);
        let map_height = rng.gen_range(MAP_MIN_HEIGHT, MAP_MAX_HEIGHT);

        let mut map = vec![];
        for y in 0..map_height {
            for x in 0..map_width {
                map.push( Tile::new(Point{x: x as i16, y: y as i16}, TileType::Wall) );
            }
        }

        let mut map = Map {
            width: map_width,
            height: map_height,
            tile_map: map,
            fov_map: tcod::map::Map::new(map_width as i32, map_height as i32),
            npcs: vec![],
        };

        // Set all tiles to be not walkable, not transparent.
        // We'll be setting these in the build_rooms and build_coridoors methods.
        map.fov_map.clear(false, false);

        let (rooms, player_start) = map.build_rooms(&mut rng);
        map.build_coridoors(&rooms, &mut rng);

        (map, player_start)
    }

    fn build_rooms(&mut self, rng: &mut rand::ThreadRng) -> (Vec<Rectangle>, Point<i16>) {
        let mut rooms = vec![];
        let mut player_start = Point{x:0, y:0};

        // Casts are to avoid overflow.
        let max_rooms = self.width as u16 * self.height as u16 / ROOM_PER_TILE as u16;

        for _ in 0..max_rooms {
            let width = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);
            let height = rng.gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE);

            let room = Rectangle::new(
                Point {
                    x: rng.gen_range(0, self.width as i16 - width as i16 - 1),
                    y: rng.gen_range(0, self.height as i16 - height as i16 - 1)
                },
                (width, height)
            );

            if !rooms.iter().any(|r: &Rectangle| r.is_intersecting(&room)) {
                self.create_room(&room).expect(ERR_MSG_ROOM);

                if rooms.len() == 0 {
                    player_start = room.centre();
                }

                rooms.push(room);
            }
        }

        (rooms, player_start)
    }

    fn build_coridoors(&mut self, rooms: &Vec<Rectangle>, rng: &mut rand::ThreadRng) {
        let mut sorted_rooms: Vec<_> = rooms.iter().map(|r| r).collect();
        let mut connected_rooms = HashSet::new();

        for room in rooms {
            sorted_rooms.sort_by(|a,b| (room.centre() - a.centre()).sqr_radius().partial_cmp(&(room.centre() - b.centre()).sqr_radius()).expect(ERR_MSG_ROOM_CMP) );

            for next in sorted_rooms.iter().skip(1).take(3) {
                if connected_rooms.contains(&(*next, room)) {
                    continue;
                }

                connected_rooms.insert((room, *next));

                let r1_centre = room.centre();
                let r2_centre = next.centre();

                // Decide whether to first tunnel horizontally or vertically.
                if rng.gen_weighted_bool(2) {
                    // Horizontal
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r1_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_v_tunnel(r2_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                } else {
                    // Vertical
                    self.create_v_tunnel(r1_centre.x, r1_centre.y..r2_centre.y).expect(ERR_MSG_TUNNEL);
                    self.create_h_tunnel(r1_centre.x..r2_centre.x, r2_centre.y).expect(ERR_MSG_TUNNEL);
                }
            }
        }
    }

    pub fn render_map<T: Console>(&self, cons: &mut T) {
        for tile in self.tile_map.iter() {
            tile.render(cons);
        }
    }

    pub fn render_npcs<T: Console>(&self, cons: &mut T) {
        for unit in self.npcs.iter() {
            if self.fov_map.is_in_fov(unit.get_x() as i32, unit.get_y() as i32) {
                unit.render(cons);
            }
        }
    }

    pub fn point_in_map(&self, Point{x,y}: Point<i16>) -> bool {
        x >= 0 && x < self.width as i16 && y >= 0 && y < self.height as i16
    }

    pub fn get_tile_type(&self, pos: Point<i16>) -> Result<TileType,()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x, y} = pos;
            Ok(self.tile_map[y as usize * self.width as usize + x as usize].tile_type)
        }
    }

    pub fn update_fov(&mut self, Point{x, y}: Point<i16>, light_radius: u8) {
        self.fov_map.compute_fov(x as i32, y as i32, light_radius as i32, true, tcod::map::FovAlgorithm::Permissive0);

        // I've opted to update the tile map here, because it doesn't make sense that
        // a function for rendering should need to mutate the object.
        // It does make this function more expensive to run, but it won't be run
        // too frequently.
        for tile in self.tile_map.iter_mut() {
            tile.is_visible = self.fov_map.is_in_fov(tile.get_x() as i32, tile.get_y() as i32);

            if tile.is_visible {
                tile.is_explored = true;
            }
        }
    }

    pub fn get_map_size(&self) -> (u8, u8) {
        (self.width, self.height)
    }

    fn create_v_tunnel(&mut self, x: i16, y_r: Range<i16>) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let y_r = if y_r.start > y_r.end {
            y_r.end+1 .. y_r.start+1
        } else {
            y_r
        };

        for y in y_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
            self.fov_map.set(x as i32, y as i32, true, true);
        }

        Ok(())
    }

    fn create_h_tunnel(&mut self, x_r: Range<i16>, y: i16) -> Result<(),()> {
        // Need to handle the case where start > end.
        // I decided to do it here to make it easier to call the function.
        // Because this is a half-open range, we need to adjust the start
        // and end to account for that.
        let x_r = if x_r.start > x_r.end {
            x_r.end+1 .. x_r.start+1
        } else {
            x_r
        };

        for x in x_r {
            let pos = Point{x:x, y:y};
            self.set_tile_type(pos, TileType::Floor)?;
            self.fov_map.set(x as i32, y as i32, true, true);
        }

        Ok(())
    }

    fn create_room(&mut self, rect: &Rectangle) -> Result<(),()> {
        for y in (rect.top_left.y+1)..rect.bottom_right.y {
            for x in (rect.top_left.x+1)..rect.bottom_right.x {
                let pos = Point{x:x, y:y};
                self.set_tile_type(pos, TileType::Floor)?;
                self.fov_map.set(x as i32, y as i32, true, true);
            }
        }

        Ok(())
    }

    fn set_tile_type(&mut self, pos: Point<i16>, new_tile: TileType) -> Result<(),()> {
        if !self.point_in_map(pos) {
            Err(())
        } else {
            let Point{x,y} = pos;
            self.tile_map[y as usize * self.width as usize + x as usize].tile_type = new_tile;

            Ok(())
        }
    }
}<|endoftext|>


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

use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLOptionElementDerived};
use dom::bindings::codegen::InheritTypes::{HTMLScriptElementDerived};
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::characterdata::CharacterData;
use dom::document::Document;
use dom::element::{AttributeHandlers, Element, HTMLOptionElementTypeId};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId};
use dom::virtualmethods::VirtualMethods;

use servo_util::atom::Atom;
use servo_util::namespace;
use servo_util::str::{DOMString, split_html_space_chars};

#[deriving(Encodable)]
#[must_root]
pub struct HTMLOptionElement {
    pub htmlelement: HTMLElement
}

impl HTMLOptionElementDerived for EventTarget {
    fn is_htmloptionelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLOptionElementTypeId))
    }
}

impl HTMLOptionElement {
    pub fn new_inherited(localName: DOMString, document: JSRef<Document>) -> HTMLOptionElement {
        HTMLOptionElement {
            htmlelement: HTMLElement::new_inherited(HTMLOptionElementTypeId, localName, document)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, document: JSRef<Document>) -> Temporary<HTMLOptionElement> {
        let element = HTMLOptionElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLOptionElementBinding::Wrap)
    }
}

fn collect_text(node: &JSRef<Node>, value: &mut DOMString) {
    let elem: JSRef<Element> = ElementCast::to_ref(*node).unwrap();
    let svg_script = elem.namespace == namespace::SVG && elem.local_name.as_slice() == "script";
    let html_script = node.is_htmlscriptelement();
    if svg_script || html_script {
        return;
    } else {
        for child in node.children() {
            if child.is_text() {
                let characterdata: JSRef<CharacterData> = CharacterDataCast::to_ref(child).unwrap();
                value.push_str(characterdata.Data().as_slice());
            } else {
                collect_text(&child, value);
            }
        }
    }
}

impl<'a> HTMLOptionElementMethods for JSRef<'a, HTMLOptionElement> {
    // http://www.whatwg.org/html/#dom-option-disabled
    make_bool_getter!(Disabled)

    // http://www.whatwg.org/html/#dom-option-disabled
    fn SetDisabled(self, disabled: bool) {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.set_bool_attribute("disabled", disabled)
    }

    // http://www.whatwg.org/html/#dom-option-text
    fn Text(&self) -> DOMString {
        let node: JSRef<Node> = NodeCast::from_ref(*self);
        let mut content = String::new();
        collect_text(&node, &mut content);
        let v: Vec<&str> = split_html_space_chars(content.as_slice()).collect();
        v.connect(" ")
    }

    // http://www.whatwg.org/html/#dom-option-text
    fn SetText(&self, value: DOMString) {
        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.SetTextContent(Some(value))
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLOptionElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            },
            _ => ()
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_parent_disabled_state_for_option();
            },
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_parent_disabled_state_for_option();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.parent_node().is_some() {
            node.check_parent_disabled_state_for_option();
        } else {
            node.check_disabled_attribute();
        }
    }
}

impl Reflectable for HTMLOptionElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>Fix upstream merge fallout<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding;
use dom::bindings::codegen::Bindings::HTMLOptionElementBinding::HTMLOptionElementMethods;
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLOptionElementDerived};
use dom::bindings::codegen::InheritTypes::{HTMLScriptElementDerived};
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::characterdata::CharacterData;
use dom::document::Document;
use dom::element::{AttributeHandlers, Element, HTMLOptionElementTypeId};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId};
use dom::virtualmethods::VirtualMethods;

use servo_util::atom::Atom;
use servo_util::namespace;
use servo_util::str::{DOMString, split_html_space_chars};

#[deriving(Encodable)]
#[must_root]
pub struct HTMLOptionElement {
    pub htmlelement: HTMLElement
}

impl HTMLOptionElementDerived for EventTarget {
    fn is_htmloptionelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLOptionElementTypeId))
    }
}

impl HTMLOptionElement {
    pub fn new_inherited(localName: DOMString, document: JSRef<Document>) -> HTMLOptionElement {
        HTMLOptionElement {
            htmlelement: HTMLElement::new_inherited(HTMLOptionElementTypeId, localName, document)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, document: JSRef<Document>) -> Temporary<HTMLOptionElement> {
        let element = HTMLOptionElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLOptionElementBinding::Wrap)
    }
}

fn collect_text(node: &JSRef<Node>, value: &mut DOMString) {
    let elem: JSRef<Element> = ElementCast::to_ref(*node).unwrap();
    let svg_script = elem.namespace == namespace::SVG && elem.local_name.as_slice() == "script";
    let html_script = node.is_htmlscriptelement();
    if svg_script || html_script {
        return;
    } else {
        for child in node.children() {
            if child.is_text() {
                let characterdata: JSRef<CharacterData> = CharacterDataCast::to_ref(child).unwrap();
                value.push_str(characterdata.Data().as_slice());
            } else {
                collect_text(&child, value);
            }
        }
    }
}

impl<'a> HTMLOptionElementMethods for JSRef<'a, HTMLOptionElement> {
    // http://www.whatwg.org/html/#dom-option-disabled
    make_bool_getter!(Disabled)

    // http://www.whatwg.org/html/#dom-option-disabled
    fn SetDisabled(self, disabled: bool) {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.set_bool_attribute("disabled", disabled)
    }

    // http://www.whatwg.org/html/#dom-option-text
    fn Text(self) -> DOMString {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        let mut content = String::new();
        collect_text(&node, &mut content);
        let v: Vec<&str> = split_html_space_chars(content.as_slice()).collect();
        v.connect(" ")
    }

    // http://www.whatwg.org/html/#dom-option-text
    fn SetText(self, value: DOMString) {
        let node: JSRef<Node> = NodeCast::from_ref(self);
        node.SetTextContent(Some(value))
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLOptionElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            },
            _ => ()
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_parent_disabled_state_for_option();
            },
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_parent_disabled_state_for_option();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.parent_node().is_some() {
            node.check_parent_disabled_state_for_option();
        } else {
            node.check_disabled_attribute();
        }
    }
}

impl Reflectable for HTMLOptionElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>