<commit_before>//! Diagnostic data structures.

#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::ops::Range;

/// A severity level for diagnostic messages.
///
/// These are ordered in the following way:
///
/// ```rust
/// use codespan_reporting::diagnostic::Severity;
///
/// assert!(Severity::Bug > Severity::Error);
/// assert!(Severity::Error > Severity::Warning);
/// assert!(Severity::Warning > Severity::Note);
/// assert!(Severity::Note > Severity::Help);
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
    /// An unexpected bug.
    Bug,
    /// An error.
    Error,
    /// A warning.
    Warning,
    /// A note.
    Note,
    /// A help message.
    Help,
}

impl Severity {
    /// We want bugs to be the maximum severity, errors next, etc...
    fn to_cmp_int(self) -> u8 {
        match self {
            Severity::Bug => 5,
            Severity::Error => 4,
            Severity::Warning => 3,
            Severity::Note => 2,
            Severity::Help => 1,
        }
    }
}

impl PartialOrd for Severity {
    fn partial_cmp(&self, other: &Severity) -> Option<std::cmp::Ordering> {
        u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle {
    /// Labels that describe the primary cause of a diagnostic.
    Primary,
    /// Labels that provide additional context for a diagnostic.
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label<FileId> {
    /// The style of the label.
    pub style: LabelStyle,
    /// The file that we are labelling.
    pub file_id: FileId,
    /// The range in bytes we are going to include in the final snippet.
    pub range: Range<usize>,
    /// An optional message to provide some additional information for the
    /// underlined code. These should not include line breaks.
    pub message: String,
}

impl<FileId> Label<FileId> {
    /// Create a new label.
    pub fn new(
        style: LabelStyle,
        file_id: FileId,
        range: impl Into<Range<usize>>,
    ) -> Label<FileId> {
        Label {
            style,
            file_id,
            range: range.into(),
            message: String::new(),
        }
    }

    /// Create a new label with a style of [`LabelStyle::Primary`].
    ///
    /// [`LabelStyle::Primary`]: LabelStyle::Primary
    pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Primary, file_id, range)
    }

    /// Create a new label with a style of [`LabelStyle::Secondary`].
    ///
    /// [`LabelStyle::Secondary`]: LabelStyle::Secondary
    pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Secondary, file_id, range)
    }

    /// Add a message to the diagnostic.
    pub fn with_message(mut self, message: impl Into<String>) -> Label<FileId> {
        self.message = message.into();
        self
    }
}

/// Represents a diagnostic message that can provide information like errors and
/// warnings to the user.
///
/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// An optional code that identifies this diagnostic.
    pub code: Option<String>,
    /// The main message associated with this diagnostic.
    ///
    /// These should not include line breaks, and in order support the 'short'
    /// diagnostic display mod, the message should be specific enough to make
    /// sense on its own, without additional context provided by labels and notes.
    pub message: String,
    /// Source labels that describe the cause of the diagnostic.
    /// The order of the labels inside the vector does not have any meaning.
    /// The labels are always arranged in the order they appear in the source code.
    pub labels: Vec<Label<FileId>>,
    /// Notes that are associated with the primary cause of the diagnostic.
    /// These can include line breaks for improved formatting.
    pub notes: Vec<String>,
}

impl<FileId> Diagnostic<FileId> {
    /// Create a new diagnostic.
    pub fn new(severity: Severity) -> Diagnostic<FileId> {
        Diagnostic {
            severity,
            code: None,
            message: String::new(),
            labels: Vec::new(),
            notes: Vec::new(),
        }
    }

    /// Create a new diagnostic with a severity of [`Severity::Bug`].
    ///
    /// [`Severity::Bug`]: Severity::Bug
    pub fn bug() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Bug)
    }

    /// Create a new diagnostic with a severity of [`Severity::Error`].
    ///
    /// [`Severity::Error`]: Severity::Error
    pub fn error() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Error)
    }

    /// Create a new diagnostic with a severity of [`Severity::Warning`].
    ///
    /// [`Severity::Warning`]: Severity::Warning
    pub fn warning() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Warning)
    }

    /// Create a new diagnostic with a severity of [`Severity::Note`].
    ///
    /// [`Severity::Note`]: Severity::Note
    pub fn note() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Note)
    }

    /// Create a new diagnostic with a severity of [`Severity::Help`].
    ///
    /// [`Severity::Help`]: Severity::Help
    pub fn help() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Help)
    }

    /// Add an error code to the diagnostic.
    pub fn with_code(mut self, code: impl Into<String>) -> Diagnostic<FileId> {
        self.code = Some(code.into());
        self
    }

    /// Add a message to the diagnostic.
    pub fn with_message(mut self, message: impl Into<String>) -> Diagnostic<FileId> {
        self.message = message.into();
        self
    }

    /// Add some labels to the diagnostic.
    pub fn with_labels(mut self, labels: Vec<Label<FileId>>) -> Diagnostic<FileId> {
        self.labels = labels;
        self
    }

    /// Add some notes to the diagnostic.
    pub fn with_notes(mut self, notes: Vec<String>) -> Diagnostic<FileId> {
        self.notes = notes;
        self
    }
}
<commit_msg>make Diagnostic documentation & methods clearer<commit_after>//! Diagnostic data structures.

#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::ops::Range;

/// A severity level for diagnostic messages.
///
/// These are ordered in the following way:
///
/// ```rust
/// use codespan_reporting::diagnostic::Severity;
///
/// assert!(Severity::Bug > Severity::Error);
/// assert!(Severity::Error > Severity::Warning);
/// assert!(Severity::Warning > Severity::Note);
/// assert!(Severity::Note > Severity::Help);
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
    /// An unexpected bug.
    Bug,
    /// An error.
    Error,
    /// A warning.
    Warning,
    /// A note.
    Note,
    /// A help message.
    Help,
}

impl Severity {
    /// We want bugs to be the maximum severity, errors next, etc...
    fn to_cmp_int(self) -> u8 {
        match self {
            Severity::Bug => 5,
            Severity::Error => 4,
            Severity::Warning => 3,
            Severity::Note => 2,
            Severity::Help => 1,
        }
    }
}

impl PartialOrd for Severity {
    fn partial_cmp(&self, other: &Severity) -> Option<std::cmp::Ordering> {
        u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle {
    /// Labels that describe the primary cause of a diagnostic.
    Primary,
    /// Labels that provide additional context for a diagnostic.
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label<FileId> {
    /// The style of the label.
    pub style: LabelStyle,
    /// The file that we are labelling.
    pub file_id: FileId,
    /// The range in bytes we are going to include in the final snippet.
    pub range: Range<usize>,
    /// An optional message to provide some additional information for the
    /// underlined code. These should not include line breaks.
    pub message: String,
}

impl<FileId> Label<FileId> {
    /// Create a new label.
    pub fn new(
        style: LabelStyle,
        file_id: FileId,
        range: impl Into<Range<usize>>,
    ) -> Label<FileId> {
        Label {
            style,
            file_id,
            range: range.into(),
            message: String::new(),
        }
    }

    /// Create a new label with a style of [`LabelStyle::Primary`].
    ///
    /// [`LabelStyle::Primary`]: LabelStyle::Primary
    pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Primary, file_id, range)
    }

    /// Create a new label with a style of [`LabelStyle::Secondary`].
    ///
    /// [`LabelStyle::Secondary`]: LabelStyle::Secondary
    pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Secondary, file_id, range)
    }

    /// Add a message to the diagnostic.
    pub fn with_message(mut self, message: impl Into<String>) -> Label<FileId> {
        self.message = message.into();
        self
    }
}

/// Represents a diagnostic message that can provide information like errors and
/// warnings to the user.
///
/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// An optional code that identifies this diagnostic.
    pub code: Option<String>,
    /// The main message associated with this diagnostic.
    ///
    /// These should not include line breaks, and in order support the 'short'
    /// diagnostic display mod, the message should be specific enough to make
    /// sense on its own, without additional context provided by labels and notes.
    pub message: String,
    /// Source labels that describe the cause of the diagnostic.
    /// The order of the labels inside the vector does not have any meaning.
    /// The labels are always arranged in the order they appear in the source code.
    pub labels: Vec<Label<FileId>>,
    /// Notes that are associated with the primary cause of the diagnostic.
    /// These can include line breaks for improved formatting.
    pub notes: Vec<String>,
}

impl<FileId> Diagnostic<FileId> {
    /// Create a new diagnostic.
    pub fn new(severity: Severity) -> Diagnostic<FileId> {
        Diagnostic {
            severity,
            code: None,
            message: String::new(),
            labels: Vec::new(),
            notes: Vec::new(),
        }
    }

    /// Create a new diagnostic with a severity of [`Severity::Bug`].
    ///
    /// [`Severity::Bug`]: Severity::Bug
    pub fn bug() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Bug)
    }

    /// Create a new diagnostic with a severity of [`Severity::Error`].
    ///
    /// [`Severity::Error`]: Severity::Error
    pub fn error() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Error)
    }

    /// Create a new diagnostic with a severity of [`Severity::Warning`].
    ///
    /// [`Severity::Warning`]: Severity::Warning
    pub fn warning() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Warning)
    }

    /// Create a new diagnostic with a severity of [`Severity::Note`].
    ///
    /// [`Severity::Note`]: Severity::Note
    pub fn note() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Note)
    }

    /// Create a new diagnostic with a severity of [`Severity::Help`].
    ///
    /// [`Severity::Help`]: Severity::Help
    pub fn help() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Help)
    }

    /// Set the error code of the diagnostic.
    pub fn with_code(mut self, code: impl Into<String>) -> Diagnostic<FileId> {
        self.code = Some(code.into());
        self
    }

    /// Set the message of the diagnostic.
    pub fn with_message(mut self, message: impl Into<String>) -> Diagnostic<FileId> {
        self.message = message.into();
        self
    }

    /// Add some labels to the diagnostic.
    pub fn with_labels(mut self, mut labels: Vec<Label<FileId>>) -> Diagnostic<FileId> {
        self.labels.append(&mut labels);
        self
    }

    /// Add some notes to the diagnostic.
    pub fn with_notes(mut self, mut notes: Vec<String>) -> Diagnostic<FileId> {
        self.notes.append(&mut notes);
        self
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::str::FromStr;
use std::fmt;
use std::collections::HashMap;

use rocket::fairing::AdHoc;
use toml;
use serde::de::{self, Deserialize, Deserializer, Visitor};

use navigation::Link;

/// This struct is used to hold meta data for contexts to be passed to [`Template::render`]
///
/// [`Template::render`]: https://api.rocket.rs/rocket_contrib/struct.Template.html#method.render
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Metadata {
    title: String,
    description: String,
    authors: Vec<Author>,
    #[serde(default)]
    sidebar: HashMap<String, SidebarItem>,
    #[serde(default)]
    menus: HashMap<String, Vec<Link>>,
    // TODO add more config fields
}

impl Metadata {
    pub fn fairing() -> AdHoc {
        AdHoc::on_attach(|rocket| {
            let mut input = String::new();
            File::open("Satellite.toml")
                .and_then(|mut f| f.read_to_string(&mut input))
                .unwrap();

            let metadata: Result<Metadata, _> = toml::from_str(input.as_str());

            match metadata {
                Ok(metadata) => Ok(rocket.manage(metadata)),
                Err(e) => {
                    println!("{}", e);
                    Err(rocket)
                }
            }
        })
    }

    // TODO remove allow(dead_code)

    /// Creates a new blanket instance of `Metadata`.
    /// All fields will be empty Strings, Vecs and HashMaps.
    #[allow(dead_code)]
    pub fn new() -> Metadata {
        Metadata {
            title: String::new(),
            description: String::new(),
            authors: Vec::new(),
            sidebar: HashMap::new(),
            menus: HashMap::new(),
        }
    }

    /// Getter for `Metadata.title`.
    #[allow(dead_code)]
    pub fn title(&self) -> &str {
        self.title.as_ref()
    }

    /// Getter for `Metadata.description`.
    #[allow(dead_code)]
    pub fn description(&self) -> &str {
        self.description.as_ref()
    }

    /// Getter for `Metadata.authors`.
    #[allow(dead_code)]
    pub fn authors(&self) -> &[Author] {
        self.authors.as_ref()
    }

    /// Getter for `Metadata.sidebar`.
    #[allow(dead_code)]
    pub fn sidebar(&self) -> &HashMap<String, SidebarItem> {
        &self.sidebar
    }

    /// Getter for `Metadata.menus`.
    #[allow(dead_code)]
    pub fn menus(&self) -> &HashMap<String, Vec<Link>> {
        &self.menus
    }
}

/// Holds the name and email address of one author.
/// Used in [`Metadata`]: struct.Metadata.html
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Author {
    name: String,
    email: String,
}

impl FromStr for Author {
    type Err = AuthorParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use regex::Regex;
        let re = Regex::new(
            r"(.*) <([a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*)>",
        ).unwrap();

        let cap = re.captures_iter(s).next().ok_or(AuthorParseError)?;
        let name = cap.get(1)
            .map(|m| m.as_str().to_string())
            .unwrap_or_default();
        let email = cap.get(2)
            .map(|m| m.as_str().to_string())
            .unwrap_or_default();

        Ok(Author { name, email })
    }
}

impl<'de> Deserialize<'de> for Author {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct AuthorStringVisitor;

        impl<'de> Visitor<'de> for AuthorStringVisitor {
            type Value = Author;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(
                    formatter,
                    "a string in the format 'Name <email@example.com>'"
                )
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Author::from_str(v).map_err(|_| {
                    E::custom(format!(
                        "'{}' is not in the format 'Name <email@example.com>'",
                        v
                    ))
                })
            }
        }

        deserializer.deserialize_str(AuthorStringVisitor)
    }
}

/// Represents a parse error for Author.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AuthorParseError;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", content = "content", rename_all = "snake_case")]
pub enum SidebarItem {
    Text(String),
    TextInset(String),
    Links(Vec<Link>),
    // TODO add dynamically loaded sidebar item
}

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

    #[test]
    fn metadata() {
        let meta = Metadata::new();
        assert!(meta.title().is_empty());
        assert!(meta.description().is_empty());
        assert!(meta.authors().is_empty());
        assert!(meta.sidebar().is_empty());
        assert!(meta.menus().is_empty());
    }

    #[test]
    fn deserialize_metadata() {
        let data = r#"
            title = "Some Title"
            description = "Some description"
            authors = [
                "Name <email@author.com>",
                "Another <another@author.net>"
            ]
        "#;

        let meta: Metadata = toml::from_str(data).unwrap();

        assert_eq!(
            meta,
            Metadata {
                title: "Some Title".to_string(),
                description: "Some description".to_string(),
                authors: vec![
                    Author {
                        name: "Name".to_string(),
                        email: "email@author.com".to_string(),
                    },
                    Author {
                        name: "Another".to_string(),
                        email: "another@author.net".to_string(),
                    },
                ],
                sidebar: HashMap::new(),
                menus: HashMap::new(),
            }
        );
    }

    #[test]
    fn deserialize_author() {
        assert_eq!(
            Ok(Author {
                name: "Random Name".to_string(),
                email: "random@mail.tld".to_string(),
            }),
            "Random Name <random@mail.tld>".parse()
        );

        assert!("".parse::<Author>().is_err());
        assert!("<>".parse::<Author>().is_err());
        assert!("<random@mail.tld>".parse::<Author>().is_err());
        assert!("Random Name".parse::<Author>().is_err());
    }

    #[test]
    fn deserialize_sidebar_item() {
        let data = r#"
            type = "text"
            content = """
            Cupcake ipsum dolor sit amet sugar plum. Cheesecake chocolate lemon drops. \
            I love chupa chups chocolate cake lollipop I love cheesecake.
            """
        "#;
        let sidebar_item: SidebarItem = toml::from_str(data).unwrap();

        assert_eq!(
            sidebar_item,
            SidebarItem::Text(String::from(
                "Cupcake ipsum dolor sit amet sugar plum. \
                   Cheesecake chocolate lemon drops. I love chupa chups chocolate cake lollipop \
                   I love cheesecake.",
            ))
        );

        let data = r#"
            type = "text_inset"
            content = """
            Cupcake ipsum dolor sit amet sugar plum. Cheesecake chocolate lemon drops. \
            I love chupa chups chocolate cake lollipop I love cheesecake.
            """
        "#;
        let sidebar_item: SidebarItem = toml::from_str(data).unwrap();

        assert_eq!(
            sidebar_item,
            SidebarItem::TextInset(String::from(
                "Cupcake ipsum dolor sit amet sugar plum. \
                   Cheesecake chocolate lemon drops. I love chupa chups chocolate cake lollipop \
                   I love cheesecake.",
            ))
        );

        let data = r#"
            type = "links"
            content = [
                { text = "Link 1", url = "https://rust-lang.org" },
                { text = "Link 2", url = "https://crates.io" },
            ]
        "#;
        let sidebar_item: SidebarItem = toml::from_str(data).unwrap();

        assert_eq!(
            sidebar_item,
            SidebarItem::Links(vec![
                Link::new("Link 1", "https://rust-lang.org"),
                Link::new("Link 2", "https://crates.io"),
            ])
        );

    }

}
<commit_msg>Fixed test deserialize_sidebar_item<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::str::FromStr;
use std::fmt;
use std::collections::HashMap;

use rocket::fairing::AdHoc;
use toml;
use serde::de::{self, Deserialize, Deserializer, Visitor};

use navigation::Link;

/// This struct is used to hold meta data for contexts to be passed to [`Template::render`]
///
/// [`Template::render`]: https://api.rocket.rs/rocket_contrib/struct.Template.html#method.render
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Metadata {
    title: String,
    description: String,
    authors: Vec<Author>,
    #[serde(default)]
    sidebar: HashMap<String, SidebarItem>,
    #[serde(default)]
    menus: HashMap<String, Vec<Link>>,
    // TODO add more config fields
}

impl Metadata {
    pub fn fairing() -> AdHoc {
        AdHoc::on_attach(|rocket| {
            let mut input = String::new();
            File::open("Satellite.toml")
                .and_then(|mut f| f.read_to_string(&mut input))
                .unwrap();

            let metadata: Result<Metadata, _> = toml::from_str(input.as_str());

            match metadata {
                Ok(metadata) => Ok(rocket.manage(metadata)),
                Err(e) => {
                    println!("{}", e);
                    Err(rocket)
                }
            }
        })
    }

    // TODO remove allow(dead_code)

    /// Creates a new blanket instance of `Metadata`.
    /// All fields will be empty Strings, Vecs and HashMaps.
    #[allow(dead_code)]
    pub fn new() -> Metadata {
        Metadata {
            title: String::new(),
            description: String::new(),
            authors: Vec::new(),
            sidebar: HashMap::new(),
            menus: HashMap::new(),
        }
    }

    /// Getter for `Metadata.title`.
    #[allow(dead_code)]
    pub fn title(&self) -> &str {
        self.title.as_ref()
    }

    /// Getter for `Metadata.description`.
    #[allow(dead_code)]
    pub fn description(&self) -> &str {
        self.description.as_ref()
    }

    /// Getter for `Metadata.authors`.
    #[allow(dead_code)]
    pub fn authors(&self) -> &[Author] {
        self.authors.as_ref()
    }

    /// Getter for `Metadata.sidebar`.
    #[allow(dead_code)]
    pub fn sidebar(&self) -> &HashMap<String, SidebarItem> {
        &self.sidebar
    }

    /// Getter for `Metadata.menus`.
    #[allow(dead_code)]
    pub fn menus(&self) -> &HashMap<String, Vec<Link>> {
        &self.menus
    }
}

/// Holds the name and email address of one author.
/// Used in [`Metadata`]: struct.Metadata.html
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Author {
    name: String,
    email: String,
}

impl FromStr for Author {
    type Err = AuthorParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use regex::Regex;
        let re = Regex::new(
            r"(.*) <([a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*)>",
        ).unwrap();

        let cap = re.captures_iter(s).next().ok_or(AuthorParseError)?;
        let name = cap.get(1)
            .map(|m| m.as_str().to_string())
            .unwrap_or_default();
        let email = cap.get(2)
            .map(|m| m.as_str().to_string())
            .unwrap_or_default();

        Ok(Author { name, email })
    }
}

impl<'de> Deserialize<'de> for Author {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct AuthorStringVisitor;

        impl<'de> Visitor<'de> for AuthorStringVisitor {
            type Value = Author;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(
                    formatter,
                    "a string in the format 'Name <email@example.com>'"
                )
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Author::from_str(v).map_err(|_| {
                    E::custom(format!(
                        "'{}' is not in the format 'Name <email@example.com>'",
                        v
                    ))
                })
            }
        }

        deserializer.deserialize_str(AuthorStringVisitor)
    }
}

/// Represents a parse error for Author.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AuthorParseError;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", content = "content", rename_all = "snake_case")]
pub enum SidebarItem {
    Text(String),
    TextInset(String),
    Links(Vec<Link>),
    // TODO add dynamically loaded sidebar item
}

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

    #[test]
    fn metadata() {
        let meta = Metadata::new();
        assert!(meta.title().is_empty());
        assert!(meta.description().is_empty());
        assert!(meta.authors().is_empty());
        assert!(meta.sidebar().is_empty());
        assert!(meta.menus().is_empty());
    }

    #[test]
    fn deserialize_metadata() {
        let data = r#"
            title = "Some Title"
            description = "Some description"
            authors = [
                "Name <email@author.com>",
                "Another <another@author.net>"
            ]
        "#;

        let meta: Metadata = toml::from_str(data).unwrap();

        assert_eq!(
            meta,
            Metadata {
                title: "Some Title".to_string(),
                description: "Some description".to_string(),
                authors: vec![
                    Author {
                        name: "Name".to_string(),
                        email: "email@author.com".to_string(),
                    },
                    Author {
                        name: "Another".to_string(),
                        email: "another@author.net".to_string(),
                    },
                ],
                sidebar: HashMap::new(),
                menus: HashMap::new(),
            }
        );
    }

    #[test]
    fn deserialize_author() {
        assert_eq!(
            Ok(Author {
                name: "Random Name".to_string(),
                email: "random@mail.tld".to_string(),
            }),
            "Random Name <random@mail.tld>".parse()
        );

        assert!("".parse::<Author>().is_err());
        assert!("<>".parse::<Author>().is_err());
        assert!("<random@mail.tld>".parse::<Author>().is_err());
        assert!("Random Name".parse::<Author>().is_err());
    }

    #[test]
    fn deserialize_sidebar_item() {
        let data = r#"
            type = "text"
            content = """Cupcake ipsum dolor sit amet sugar plum. Cheesecake chocolate lemon drops. \
            I love chupa chups chocolate cake lollipop I love cheesecake."""
        "#;
        let sidebar_item: SidebarItem = toml::from_str(data).unwrap();

        assert_eq!(
            sidebar_item,
            SidebarItem::Text(String::from(
                "Cupcake ipsum dolor sit amet sugar plum. \
                   Cheesecake chocolate lemon drops. I love chupa chups chocolate cake lollipop \
                   I love cheesecake.",
            ))
        );

        let data = r#"
            type = "text_inset"
            content = """Cupcake ipsum dolor sit amet sugar plum. Cheesecake chocolate lemon drops. \
            I love chupa chups chocolate cake lollipop I love cheesecake."""
        "#;
        let sidebar_item: SidebarItem = toml::from_str(data).unwrap();

        assert_eq!(
            sidebar_item,
            SidebarItem::TextInset(String::from(
                "Cupcake ipsum dolor sit amet sugar plum. \
                   Cheesecake chocolate lemon drops. I love chupa chups chocolate cake lollipop \
                   I love cheesecake.",
            ))
        );

        let data = r#"
            type = "links"
            content = [
                { text = "Link 1", url = "https://rust-lang.org" },
                { text = "Link 2", url = "https://crates.io" },
            ]
        "#;
        let sidebar_item: SidebarItem = toml::from_str(data).unwrap();

        assert_eq!(
            sidebar_item,
            SidebarItem::Links(vec![
                Link::new("Link 1", "https://rust-lang.org"),
                Link::new("Link 2", "https://crates.io"),
            ])
        );

    }

}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use std::slice;
use rand::Rng;

#[derive(Eq, PartialEq)]
enum Move {
    Rock,
    Paper,
    Scissors,
}

#[derive(Debug)]
enum GameResult {
    Human,
    Computer,
    Draw,
}

struct Game {
    frequencies: [u32; 3],
}

impl Move {
    fn beaten_by(&self) ->  Move {
        match *self {
            Move::Rock => Move::Paper,
            Move::Paper => Move::Scissors,
            Move::Scissors => Move::Rock,
        }
    }

    fn variants() -> slice::Iter<'static, Move> {
        static VARIANTS: &'static [Move] = &[Move::Rock, Move::Paper, Move::Scissors];

        VARIANTS.iter()
    }
}

impl Game {
    fn new() -> Game {
        Game{frequencies: [0, 0, 0]}
    }

    fn increment_frequency(&mut self, m: &Move) {
        let i = Move::variants().position(|n| n == m).expect("Unknown frequency.");
        self.frequencies[i] += 1;
    }

    fn pick(&self) -> Move {
        let total = self.frequencies.iter().fold(0, |t, n| t + n);
        let guess = rand::thread_rng().gen_range(0, total + 1);
        let mut sum: u32 = 0;

        for (&f, c) in self.frequencies.iter().zip(Move::variants()) {
            sum += f;

            if guess <= sum {
                return c.beaten_by();
            }
        }

        return Move::Rock;
    }

    fn play(&mut self, human: &Move) -> GameResult {
        let computer = self.pick();

        self.increment_frequency(&human);

        if human.beaten_by() == computer {
            GameResult::Computer
        } else if computer.beaten_by() == *human {
            GameResult::Human
        } else {
            GameResult::Draw
        }
    }
}

fn main() {
   let mut game = Game::new();

   loop {
       println!("Enter a guess (r, p, s);");

       let mut input = String::new();

       io::stdin()
           .read_line(&mut input)
           .ok()
           .expect("Could not read input.");

       let human = match input.trim() {
           "r" => Move::Rock,
           "p" => Move::Paper,
           "s" => Move::Scissors,
           _ => { continue; },
       };

       println!("Winner: {:?}", game.play(&human));
   }
}
<commit_msg>Final refactor<commit_after>extern crate rand;

use std::io;
use std::slice;
use rand::Rng;

#[derive(Eq, PartialEq)]
enum Move {
    Rock,
    Paper,
    Scissors,
}

#[derive(Debug)]
enum GameResult {
    Human,
    Computer,
    Draw,
}

struct Game {
    frequencies: [u32; 3],
}

impl Move {
    fn beaten_by(&self) ->  Move {
        match *self {
            Move::Rock => Move::Paper,
            Move::Paper => Move::Scissors,
            Move::Scissors => Move::Rock,
        }
    }

    fn variants() -> slice::Iter<'static, Move> {
        static VARIANTS: &'static [Move] = &[Move::Rock, Move::Paper, Move::Scissors];
        VARIANTS.iter()
    }
}

impl Game {
    fn new() -> Game {
        Game{frequencies: [0, 0, 0]}
    }

    fn increment_frequency(&mut self, m: &Move) {
        let i = Move::variants().position(|n| n == m).expect("Unknown frequency.");
        self.frequencies[i] += 1;
    }

    fn pick(&self) -> Move {
        let total = self.frequencies.iter().fold(0, |t, n| t + n);
        let guess = rand::thread_rng().gen_range(0, total + 1);
        let mut sum: u32 = 0;

        for (&f, c) in self.frequencies.iter().zip(Move::variants()) {
            sum += f;

            if guess <= sum {
                return c.beaten_by();
            }
        }

        return Move::Rock;
    }

    fn play(&mut self, human: &Move) -> GameResult {
        let computer = self.pick();

        self.increment_frequency(&human);

        if human.beaten_by() == computer {
            GameResult::Computer
        } else if computer.beaten_by() == *human {
            GameResult::Human
        } else {
            GameResult::Draw
        }
    }
}

fn main() {
   let mut game = Game::new();

   loop {
       println!("Enter a guess (r, p, s): ");

       let mut input = String::new();

       io::stdin()
           .read_line(&mut input)
           .ok()
           .expect("Could not read input.");

       let human = match input.trim() {
           "r" => Move::Rock,
           "p" => Move::Paper,
           "s" => Move::Scissors,
           _ => { continue; },
       };

       println!("Winner: {:?}", game.play(&human));
   }
}
<|endoftext|>


<commit_before>//! Channel that delivers messages periodically.
//!
//! Messages cannot be sent into this kind of channel; they are materialized on demand.

use std::thread;
use std::time::{Duration, Instant};

use crossbeam_utils::atomic::AtomicCell;

use context::Context;
use err::{RecvTimeoutError, TryRecvError};
use select::{Operation, SelectHandle, Token};

/// Result of a receive operation.
pub type TickToken = Option<Instant>;

/// Channel that delivers messages periodically.
pub struct Channel {
    /// The instant at which the next message will be delivered.
    delivery_time: AtomicCell<Instant>,

    /// The time interval in which messages get delivered.
    duration: Duration,
}

impl Channel {
    /// Creates a channel that delivers messages periodically.
    #[inline]
    pub fn new(dur: Duration) -> Self {
        Channel {
            delivery_time: AtomicCell::new(Instant::now() + dur),
            duration: dur,
        }
    }

    /// Attempts to receive a message without blocking.
    #[inline]
    pub fn try_recv(&self) -> Result<Instant, TryRecvError> {
        loop {
            let now = Instant::now();
            let delivery_time = self.delivery_time.load();

            if now < delivery_time {
                return Err(TryRecvError::Empty);
            }

            if self
                .delivery_time
                .compare_exchange(delivery_time, now + self.duration)
                .is_ok()
            {
                return Ok(delivery_time);
            }
        }
    }

    /// Receives a message from the channel.
    #[inline]
    pub fn recv(&self, deadline: Option<Instant>) -> Result<Instant, RecvTimeoutError> {
        loop {
            let delivery_time = self.delivery_time.load();
            let now = Instant::now();

            if let Some(d) = deadline {
                if d < delivery_time {
                    if now < d {
                        thread::sleep(d - now);
                    }
                    return Err(RecvTimeoutError::Timeout);
                }
            }

            if self
                .delivery_time
                .compare_exchange(delivery_time, delivery_time.max(now) + self.duration)
                .is_ok()
            {
                if now < delivery_time {
                    thread::sleep(delivery_time - now);
                }
                return Ok(delivery_time.max(now));
            }
        }
    }

    /// Reads a message from the channel.
    #[inline]
    pub unsafe fn read(&self, token: &mut Token) -> Result<Instant, ()> {
        token.tick.ok_or(())
    }

    /// Returns `true` if the channel is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        Instant::now() < self.delivery_time.load()
    }

    /// Returns `true` if the channel is full.
    #[inline]
    pub fn is_full(&self) -> bool {
        !self.is_empty()
    }

    /// Returns the number of messages in the channel.
    #[inline]
    pub fn len(&self) -> usize {
        if self.is_empty() {
            0
        } else {
            1
        }
    }

    /// Returns the capacity of the channel.
    #[inline]
    pub fn capacity(&self) -> Option<usize> {
        Some(1)
    }
}

impl SelectHandle for Channel {
    #[inline]
    fn try_select(&self, token: &mut Token) -> bool {
        match self.try_recv() {
            Ok(msg) => {
                token.tick = Some(msg);
                true
            }
            Err(TryRecvError::Disconnected) => {
                token.tick = None;
                true
            }
            Err(TryRecvError::Empty) => false,
        }
    }

    #[inline]
    fn deadline(&self) -> Option<Instant> {
        Some(self.delivery_time.load())
    }

    #[inline]
    fn register(&self, _oper: Operation, _cx: &Context) -> bool {
        self.is_ready()
    }

    #[inline]
    fn unregister(&self, _oper: Operation) {}

    #[inline]
    fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
        self.try_select(token)
    }

    #[inline]
    fn is_ready(&self) -> bool {
        !self.is_empty()
    }

    #[inline]
    fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
        self.is_ready()
    }

    #[inline]
    fn unwatch(&self, _oper: Operation) {}
}
<commit_msg>Fix delivery time in recv()<commit_after>//! Channel that delivers messages periodically.
//!
//! Messages cannot be sent into this kind of channel; they are materialized on demand.

use std::thread;
use std::time::{Duration, Instant};

use crossbeam_utils::atomic::AtomicCell;

use context::Context;
use err::{RecvTimeoutError, TryRecvError};
use select::{Operation, SelectHandle, Token};

/// Result of a receive operation.
pub type TickToken = Option<Instant>;

/// Channel that delivers messages periodically.
pub struct Channel {
    /// The instant at which the next message will be delivered.
    delivery_time: AtomicCell<Instant>,

    /// The time interval in which messages get delivered.
    duration: Duration,
}

impl Channel {
    /// Creates a channel that delivers messages periodically.
    #[inline]
    pub fn new(dur: Duration) -> Self {
        Channel {
            delivery_time: AtomicCell::new(Instant::now() + dur),
            duration: dur,
        }
    }

    /// Attempts to receive a message without blocking.
    #[inline]
    pub fn try_recv(&self) -> Result<Instant, TryRecvError> {
        loop {
            let now = Instant::now();
            let delivery_time = self.delivery_time.load();

            if now < delivery_time {
                return Err(TryRecvError::Empty);
            }

            if self
                .delivery_time
                .compare_exchange(delivery_time, now + self.duration)
                .is_ok()
            {
                return Ok(delivery_time);
            }
        }
    }

    /// Receives a message from the channel.
    #[inline]
    pub fn recv(&self, deadline: Option<Instant>) -> Result<Instant, RecvTimeoutError> {
        loop {
            let delivery_time = self.delivery_time.load();
            let now = Instant::now();

            if let Some(d) = deadline {
                if d < delivery_time {
                    if now < d {
                        thread::sleep(d - now);
                    }
                    return Err(RecvTimeoutError::Timeout);
                }
            }

            if self
                .delivery_time
                .compare_exchange(delivery_time, delivery_time.max(now) + self.duration)
                .is_ok()
            {
                if now < delivery_time {
                    thread::sleep(delivery_time - now);
                }
                return Ok(delivery_time);
            }
        }
    }

    /// Reads a message from the channel.
    #[inline]
    pub unsafe fn read(&self, token: &mut Token) -> Result<Instant, ()> {
        token.tick.ok_or(())
    }

    /// Returns `true` if the channel is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        Instant::now() < self.delivery_time.load()
    }

    /// Returns `true` if the channel is full.
    #[inline]
    pub fn is_full(&self) -> bool {
        !self.is_empty()
    }

    /// Returns the number of messages in the channel.
    #[inline]
    pub fn len(&self) -> usize {
        if self.is_empty() {
            0
        } else {
            1
        }
    }

    /// Returns the capacity of the channel.
    #[inline]
    pub fn capacity(&self) -> Option<usize> {
        Some(1)
    }
}

impl SelectHandle for Channel {
    #[inline]
    fn try_select(&self, token: &mut Token) -> bool {
        match self.try_recv() {
            Ok(msg) => {
                token.tick = Some(msg);
                true
            }
            Err(TryRecvError::Disconnected) => {
                token.tick = None;
                true
            }
            Err(TryRecvError::Empty) => false,
        }
    }

    #[inline]
    fn deadline(&self) -> Option<Instant> {
        Some(self.delivery_time.load())
    }

    #[inline]
    fn register(&self, _oper: Operation, _cx: &Context) -> bool {
        self.is_ready()
    }

    #[inline]
    fn unregister(&self, _oper: Operation) {}

    #[inline]
    fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
        self.try_select(token)
    }

    #[inline]
    fn is_ready(&self) -> bool {
        !self.is_empty()
    }

    #[inline]
    fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
        self.is_ready()
    }

    #[inline]
    fn unwatch(&self, _oper: Operation) {}
}
<|endoftext|>


<commit_before>use kay::{ActorSystem, World, Actor, Fate};
use compact::{CVec, COption};
use descartes::P2;
use stagemaster::UserInterfaceID;

use transport::lane::{Lane, LaneID};
use simulation::Ticks;
use construction::{ConstructionID, Constructable, ConstructableID};
use planning::Prototype;

pub mod rendering;
pub mod architecture;

use economy::households::HouseholdID;
use transport::pathfinding::PreciseLocation;
use economy::immigration_and_development::ImmigrationManagerID;
use land_use::zone_planning::Lot;

#[derive(Copy, Clone)]
pub struct Unit(Option<HouseholdID>, UnitType);

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum UnitType {
    Dwelling,
    Retail,
    Agriculture,
    Mill,
    Bakery,
    NeighboringTownTrade,
}

#[derive(Copy, Clone)]
pub struct UnitIdx(usize);

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BuildingStyle {
    FamilyHouse,
    GroceryShop,
    Field,
    Mill,
    Bakery,
    NeighboringTownConnection,
}

#[derive(Compact, Clone)]
pub struct Building {
    id: BuildingID,
    units: CVec<Unit>,
    lot: Lot,
    pub location: Option<PreciseLocation>,
    style: BuildingStyle,
    being_destroyed_for: COption<ConstructionID>,
    started_reconnect: bool,
}

//use stagemaster::geometry::add_debug_line;

impl Building {
    pub fn spawn(id: BuildingID, style: BuildingStyle, lot: &Lot, world: &mut World) -> Building {
        println!("Spawned building {:?}", style);

        rendering::on_add(id, lot, style, world);

        Simulation::local_first(world).wake_up_in(
            Ticks::from(
                Duration::from_minutes(10),
            ),
            id.into(),
            world,
        );

        Building {
            id,
            units: units_for_style(style),
            lot: lot.clone(),
            location: None,
            style,
            being_destroyed_for: COption(None),
            started_reconnect: false,
        }
    }

    pub fn try_offer_unit(
        &mut self,
        required_unit_type: UnitType,
        requester: ImmigrationManagerID,
        world: &mut World,
    ) {
        if self.being_destroyed_for.is_none() {
            if let Some(idx) = self.units.iter().position(|&Unit(household, unit_type)| {
                household.is_none() && unit_type == required_unit_type
            })
            {
                requester.on_unit_offer(self.id, UnitIdx(idx), world);
            }
        }
    }

    pub fn add_household(&mut self, household: HouseholdID, unit: UnitIdx, _: &mut World) {
        self.units[unit.0].0 = Some(household);
    }

    pub fn remove_household(&mut self, household: HouseholdID, world: &mut World) {
        let position = self.units
            .iter()
            .position(|&Unit(user, _)| user == Some(household))
            .expect("Tried to remove a household not in the building");
        self.units[position].0 = None;

        if self.being_destroyed_for.is_some() && self.all_households().is_empty() {
            self.id.finally_destroy(world);
        }
    }

    pub fn all_households(&self) -> Vec<HouseholdID> {
        self.units
            .iter()
            .filter_map(|&Unit(user, _)| user)
            .collect()
    }

    pub fn finally_destroy(&mut self, world: &mut World) -> Fate {
        rendering::on_destroy(self.id, world);
        if let Some(location) = self.location {
            location.node.remove_attachee(self.id_as(), world);
        }
        self.being_destroyed_for.unwrap().action_done(
            self.id.into(),
            world,
        );
        Fate::Die
    }
}

impl Constructable for Building {
    fn morph(&mut self, new_prototype: &Prototype, report_to: ConstructionID, world: &mut World) {
        if let Prototype::Lot(ref lot_prototype) = *new_prototype {
            self.lot = lot_prototype.lot.clone();
            report_to.action_done(self.id.into(), world);
        } else {
            unreachable!()
        }
    }

    fn destruct(&mut self, report_to: ConstructionID, world: &mut World) -> Fate {
        for household in &self.all_households() {
            household.destroy(world);
        }

        self.being_destroyed_for = COption(Some(report_to));

        Fate::Live
    }
}

use transport::pathfinding::{Location, Attachee, AttacheeID};
use simulation::{Simulation, Sleeper, SleeperID, Duration};

impl Attachee for Building {
    fn location_changed(
        &mut self,
        _old: Option<Location>,
        maybe_new: Option<Location>,
        world: &mut World,
    ) {
        if let Some(new) = maybe_new {
            self.location
                .as_mut()
                .expect("Only an existing location can change")
                .location = new;
        } else {
            self.location = None;
            Simulation::local_first(world).wake_up_in(
                Ticks::from(
                    Duration::from_minutes(10),
                ),
                self.id_as(),
                world,
            );
        }
    }
}

impl Sleeper for Building {
    fn wake(&mut self, _instant: Instant, world: &mut World) {
        if self.started_reconnect {
            if self.location.is_none() {
                // TODO: do we still need to destroy here?
            } else {
                self.started_reconnect = false;
            }
        } else {
            Lane::global_broadcast(world).try_reconnect_building(
                self.id,
                self.lot.center_point(),
                world,
            );
            Simulation::local_first(world).wake_up_in(
                Ticks::from(
                    Duration::from_minutes(10),
                ),
                self.id_as(),
                world,
            );
            self.started_reconnect = true;
        }
    }
}

impl Building {
    pub fn reconnect(
        &mut self,
        new_location: PreciseLocation,
        _new_connection_point: P2,
        world: &mut World,
    ) {
        if self.location.is_none() {
            self.location = Some(new_location);
            new_location.node.add_attachee(self.id_as(), world);
        }
    }
}

use transport::pathfinding::{RoughLocation, RoughLocationID, RoughLocationResolve};
use simulation::Instant;

impl RoughLocation for Building {
    fn resolve(&self) -> RoughLocationResolve {
        RoughLocationResolve::Done(self.location, self.lot.center_point())
    }
}

const FAMILIES_PER_NEIGHBORING_TOWN: usize = 5;

pub fn units_for_style(style: BuildingStyle) -> CVec<Unit> {
    match style {
        BuildingStyle::FamilyHouse => vec![Unit(None, UnitType::Dwelling)],
        BuildingStyle::GroceryShop => vec![Unit(None, UnitType::Retail)],
        BuildingStyle::Bakery => vec![Unit(None, UnitType::Bakery)],
        BuildingStyle::Mill => vec![Unit(None, UnitType::Mill)],
        BuildingStyle::Field => vec![Unit(None, UnitType::Agriculture)],
        BuildingStyle::NeighboringTownConnection => {
            Some(Unit(None, UnitType::NeighboringTownTrade))
                .into_iter()
                .chain(vec![
                    Unit(None, UnitType::Dwelling);
                    FAMILIES_PER_NEIGHBORING_TOWN
                ])
                .collect()
        }
    }.into()
}

pub const MIN_ROAD_LENGTH_TO_TOWN: f32 = 4000.0;
const MIN_NEIGHBORING_TOWN_DISTANCE: f32 = 2000.0;

pub const MIN_LANE_BUILDING_DISTANCE: f32 = 15.0;

#[derive(Compact, Clone, Default)]
pub struct BuildingPlanResultDelta {
    buildings_to_destroy: CVec<BuildingID>,
}

#[derive(Compact, Clone, Default)]
pub struct MaterializedBuildings {
    buildings: CVec<(P2, BuildingID, LaneID)>,
}
pub fn setup(system: &mut ActorSystem, user_interface: UserInterfaceID) {
    system.register::<Building>();
    rendering::setup(system, user_interface);

    kay_auto::auto_setup(system);
}

mod kay_auto;
pub use self::kay_auto::*;
<commit_msg>Fix bugs with empty buildings never being destroyed and add gfx morphing<commit_after>use kay::{ActorSystem, World, Actor, Fate};
use compact::{CVec, COption};
use descartes::P2;
use stagemaster::UserInterfaceID;

use transport::lane::{Lane, LaneID};
use simulation::Ticks;
use construction::{ConstructionID, Constructable, ConstructableID};
use planning::Prototype;

pub mod rendering;
pub mod architecture;

use economy::households::HouseholdID;
use transport::pathfinding::PreciseLocation;
use economy::immigration_and_development::ImmigrationManagerID;
use land_use::zone_planning::Lot;

#[derive(Copy, Clone)]
pub struct Unit(Option<HouseholdID>, UnitType);

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum UnitType {
    Dwelling,
    Retail,
    Agriculture,
    Mill,
    Bakery,
    NeighboringTownTrade,
}

#[derive(Copy, Clone)]
pub struct UnitIdx(usize);

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BuildingStyle {
    FamilyHouse,
    GroceryShop,
    Field,
    Mill,
    Bakery,
    NeighboringTownConnection,
}

#[derive(Compact, Clone)]
pub struct Building {
    id: BuildingID,
    units: CVec<Unit>,
    lot: Lot,
    pub location: Option<PreciseLocation>,
    style: BuildingStyle,
    being_destroyed_for: COption<ConstructionID>,
    started_reconnect: bool,
}

//use stagemaster::geometry::add_debug_line;

impl Building {
    pub fn spawn(id: BuildingID, style: BuildingStyle, lot: &Lot, world: &mut World) -> Building {
        println!("Spawned building {:?}", style);

        rendering::on_add(id, lot, style, world);

        Simulation::local_first(world).wake_up_in(
            Ticks::from(
                Duration::from_minutes(10),
            ),
            id.into(),
            world,
        );

        Building {
            id,
            units: units_for_style(style),
            lot: lot.clone(),
            location: None,
            style,
            being_destroyed_for: COption(None),
            started_reconnect: false,
        }
    }

    pub fn try_offer_unit(
        &mut self,
        required_unit_type: UnitType,
        requester: ImmigrationManagerID,
        world: &mut World,
    ) {
        if self.being_destroyed_for.is_none() {
            if let Some(idx) = self.units.iter().position(|&Unit(household, unit_type)| {
                household.is_none() && unit_type == required_unit_type
            })
            {
                requester.on_unit_offer(self.id, UnitIdx(idx), world);
            }
        }
    }

    pub fn add_household(&mut self, household: HouseholdID, unit: UnitIdx, _: &mut World) {
        self.units[unit.0].0 = Some(household);
    }

    pub fn remove_household(&mut self, household: HouseholdID, world: &mut World) {
        let position = self.units
            .iter()
            .position(|&Unit(user, _)| user == Some(household))
            .expect("Tried to remove a household not in the building");
        self.units[position].0 = None;

        if self.being_destroyed_for.is_some() && self.all_households().is_empty() {
            self.id.finally_destroy(world);
        }
    }

    pub fn all_households(&self) -> Vec<HouseholdID> {
        self.units
            .iter()
            .filter_map(|&Unit(user, _)| user)
            .collect()
    }

    pub fn finally_destroy(&mut self, world: &mut World) -> Fate {
        rendering::on_destroy(self.id, world);
        if let Some(location) = self.location {
            location.node.remove_attachee(self.id_as(), world);
        }
        self.being_destroyed_for.unwrap().action_done(
            self.id.into(),
            world,
        );
        Fate::Die
    }
}

impl Constructable for Building {
    fn morph(&mut self, new_prototype: &Prototype, report_to: ConstructionID, world: &mut World) {
        if let Prototype::Lot(ref lot_prototype) = *new_prototype {
            self.lot = lot_prototype.lot.clone();
            rendering::on_destroy(self.id, world);
            rendering::on_add(self.id, &self.lot, self.style, world);
            report_to.action_done(self.id.into(), world);
        } else {
            unreachable!()
        }
    }

    fn destruct(&mut self, report_to: ConstructionID, world: &mut World) -> Fate {
        self.being_destroyed_for = COption(Some(report_to));

        if self.all_households().is_empty() {
            self.finally_destroy(world)
        } else {
            for household in &self.all_households() {
                household.destroy(world);
            }

            Fate::Live
        }
    }
}

use transport::pathfinding::{Location, Attachee, AttacheeID};
use simulation::{Simulation, Sleeper, SleeperID, Duration};

impl Attachee for Building {
    fn location_changed(
        &mut self,
        _old: Option<Location>,
        maybe_new: Option<Location>,
        world: &mut World,
    ) {
        if let Some(new) = maybe_new {
            self.location
                .as_mut()
                .expect("Only an existing location can change")
                .location = new;
        } else {
            self.location = None;
            Simulation::local_first(world).wake_up_in(
                Ticks::from(
                    Duration::from_minutes(10),
                ),
                self.id_as(),
                world,
            );
        }
    }
}

impl Sleeper for Building {
    fn wake(&mut self, _instant: Instant, world: &mut World) {
        if self.started_reconnect {
            if self.location.is_none() {
                // TODO: do we still need to destroy here?
            } else {
                self.started_reconnect = false;
            }
        } else {
            Lane::global_broadcast(world).try_reconnect_building(
                self.id,
                self.lot.center_point(),
                world,
            );
            Simulation::local_first(world).wake_up_in(
                Ticks::from(
                    Duration::from_minutes(10),
                ),
                self.id_as(),
                world,
            );
            self.started_reconnect = true;
        }
    }
}

impl Building {
    pub fn reconnect(
        &mut self,
        new_location: PreciseLocation,
        _new_connection_point: P2,
        world: &mut World,
    ) {
        if self.location.is_none() {
            self.location = Some(new_location);
            new_location.node.add_attachee(self.id_as(), world);
        }
    }
}

use transport::pathfinding::{RoughLocation, RoughLocationID, RoughLocationResolve};
use simulation::Instant;

impl RoughLocation for Building {
    fn resolve(&self) -> RoughLocationResolve {
        RoughLocationResolve::Done(self.location, self.lot.center_point())
    }
}

const FAMILIES_PER_NEIGHBORING_TOWN: usize = 5;

pub fn units_for_style(style: BuildingStyle) -> CVec<Unit> {
    match style {
        BuildingStyle::FamilyHouse => vec![Unit(None, UnitType::Dwelling)],
        BuildingStyle::GroceryShop => vec![Unit(None, UnitType::Retail)],
        BuildingStyle::Bakery => vec![Unit(None, UnitType::Bakery)],
        BuildingStyle::Mill => vec![Unit(None, UnitType::Mill)],
        BuildingStyle::Field => vec![Unit(None, UnitType::Agriculture)],
        BuildingStyle::NeighboringTownConnection => {
            Some(Unit(None, UnitType::NeighboringTownTrade))
                .into_iter()
                .chain(vec![
                    Unit(None, UnitType::Dwelling);
                    FAMILIES_PER_NEIGHBORING_TOWN
                ])
                .collect()
        }
    }.into()
}

pub const MIN_ROAD_LENGTH_TO_TOWN: f32 = 4000.0;
const MIN_NEIGHBORING_TOWN_DISTANCE: f32 = 2000.0;

pub const MIN_LANE_BUILDING_DISTANCE: f32 = 15.0;

#[derive(Compact, Clone, Default)]
pub struct BuildingPlanResultDelta {
    buildings_to_destroy: CVec<BuildingID>,
}

#[derive(Compact, Clone, Default)]
pub struct MaterializedBuildings {
    buildings: CVec<(P2, BuildingID, LaneID)>,
}
pub fn setup(system: &mut ActorSystem, user_interface: UserInterfaceID) {
    system.register::<Building>();
    rendering::setup(system, user_interface);

    kay_auto::auto_setup(system);
}

mod kay_auto;
pub use self::kay_auto::*;
<|endoftext|>


<commit_before>use {HasLua, CopyRead, ConsumeRead, LoadedVariable, Push, Index};
use ffi;

#[unstable]
pub struct LuaTable<'var, L> {
    variable: LoadedVariable<'var, L>
}

impl<'var, L: HasLua> HasLua for LuaTable<'var, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.variable.use_lua()
    }
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
#[unstable]
pub struct LuaTableIterator<'var, 'table, L> {
    table: &'table mut LuaTable<'var, L>
}

impl<'var, 'table, L: HasLua> HasLua for LuaTableIterator<'var, 'table, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.table.use_lua()
    }
}

impl<'var, L: HasLua> ConsumeRead<'var, L> for LuaTable<'var, L> {
    fn read_from_variable(mut var: LoadedVariable<'var, L>)
        -> Result<LuaTable<'var, L>, LoadedVariable<'var, L>>
    {
        if unsafe { ffi::lua_istable(var.use_lua(), -1) } {
            Ok(LuaTable{ variable: var })
        } else {
            Err(var)
        }
    }
}

impl<'var, L: HasLua> LuaTable<'var, L> {
    pub fn iter<'me>(&'me mut self)
        -> LuaTableIterator<'var, 'me, L>
    {
        unsafe { ffi::lua_pushnil(self.variable.use_lua()) };
        LuaTableIterator { table: self }
    }

    pub fn load<'a, R: ConsumeRead<'a, LuaTable<'var, L>>, I: Index<LuaTable<'var, L>>>(&'a mut self, index: I) -> Option<R> {
        index.push_to_lua(self);
        unsafe { ffi::lua_gettable(self.use_lua(), -2); }
        let var = LoadedVariable{lua: self, size: 1};
        ConsumeRead::read_from_variable(var).ok()
    }

    pub fn load_table<'a, I: Index<LuaTable<'var, L>>>(&'a mut self, index: I) -> Option<LuaTable<'a, LuaTable<'var, L>>> {
        self.load(index)
    }

    pub fn get<R: CopyRead<LuaTable<'var, L>>, I: Index<LuaTable<'var, L>>>(&mut self, index: I) -> Option<R> {
        index.push_to_lua(self);
        unsafe { ffi::lua_gettable(self.use_lua(), -2); }
        let value = CopyRead::read_from_lua(self, -1);
        unsafe { ffi::lua_pop(self.use_lua(), 1); }
        value
    }

    pub fn set<I: Index<LuaTable<'var, L>>, V: Push<LuaTable<'var, L>>>(&mut self, index: I, value: V) {
        index.push_to_lua(self);
        value.push_to_lua(self);
        unsafe { ffi::lua_settable(self.use_lua(), -3); }
    }

    // Obtains or create the metatable of the table
    pub fn get_or_create_metatable(mut self) -> LuaTable<'var, L> {
        let result = unsafe { ffi::lua_getmetatable(self.variable.use_lua(), -1) };

        if result == 0 {
            unsafe {
                ffi::lua_newtable(self.variable.use_lua());
                ffi::lua_setmetatable(self.variable.use_lua(), -2);
                let r = ffi::lua_getmetatable(self.variable.use_lua(), -1);
                assert!(r != 0);
            }
        }

        // note: it would be cleaner to create another table, but cannot manage to make it compile
        self.variable.size += 1;
        self
    }
}

impl<'a, 'b, L: HasLua, K: CopyRead<LuaTableIterator<'a, 'b, L>>, V: CopyRead<LuaTableIterator<'a, 'b, L>>>
    Iterator<Option<(K, V)>> for LuaTableIterator<'a, 'b, L>
{
    fn next(&mut self)
        -> Option<Option<(K,V)>>
    {
        // this call pushes the next key and value on the stack
        if unsafe { ffi::lua_next(self.table.use_lua(), -2) } == 0 {
            return None
        }

        let key = CopyRead::read_from_lua(self, -2);
        let value = CopyRead::read_from_lua(self, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { ffi::lua_pop(self.table.use_lua(), 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

// TODO: this destructor crashes the compiler
/*impl<'a, 'b> Drop for LuaTableIterator<'a, 'b> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.table.variable.lua.lua, 1) }
    }
}*/
<commit_msg>Bugfix with iterators cleanup<commit_after>use {HasLua, CopyRead, ConsumeRead, LoadedVariable, Push, Index};
use ffi;

#[unstable]
pub struct LuaTable<'var, L> {
    variable: LoadedVariable<'var, L>
}

impl<'var, L: HasLua> HasLua for LuaTable<'var, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.variable.use_lua()
    }
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
#[unstable]
pub struct LuaTableIterator<'var, 'table, L> {
    table: &'table mut LuaTable<'var, L>,
    finished: bool,     // if true, the key is not on the stack anymore
}

impl<'var, 'table, L: HasLua> HasLua for LuaTableIterator<'var, 'table, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.table.use_lua()
    }
}

impl<'var, L: HasLua> ConsumeRead<'var, L> for LuaTable<'var, L> {
    fn read_from_variable(mut var: LoadedVariable<'var, L>)
        -> Result<LuaTable<'var, L>, LoadedVariable<'var, L>>
    {
        if unsafe { ffi::lua_istable(var.use_lua(), -1) } {
            Ok(LuaTable{ variable: var })
        } else {
            Err(var)
        }
    }
}

impl<'var, L: HasLua> LuaTable<'var, L> {
    pub fn iter<'me>(&'me mut self)
        -> LuaTableIterator<'var, 'me, L>
    {
        unsafe { ffi::lua_pushnil(self.variable.use_lua()) };
        LuaTableIterator{table: self, finished: false}
    }

    pub fn load<'a, R: ConsumeRead<'a, LuaTable<'var, L>>, I: Index<LuaTable<'var, L>>>(&'a mut self, index: I) -> Option<R> {
        index.push_to_lua(self);
        unsafe { ffi::lua_gettable(self.use_lua(), -2); }
        let var = LoadedVariable{lua: self, size: 1};
        ConsumeRead::read_from_variable(var).ok()
    }

    pub fn load_table<'a, I: Index<LuaTable<'var, L>>>(&'a mut self, index: I) -> Option<LuaTable<'a, LuaTable<'var, L>>> {
        self.load(index)
    }

    pub fn get<R: CopyRead<LuaTable<'var, L>>, I: Index<LuaTable<'var, L>>>(&mut self, index: I) -> Option<R> {
        index.push_to_lua(self);
        unsafe { ffi::lua_gettable(self.use_lua(), -2); }
        let value = CopyRead::read_from_lua(self, -1);
        unsafe { ffi::lua_pop(self.use_lua(), 1); }
        value
    }

    pub fn set<I: Index<LuaTable<'var, L>>, V: Push<LuaTable<'var, L>>>(&mut self, index: I, value: V) {
        index.push_to_lua(self);
        value.push_to_lua(self);
        unsafe { ffi::lua_settable(self.use_lua(), -3); }
    }

    // Obtains or create the metatable of the table
    pub fn get_or_create_metatable(mut self) -> LuaTable<'var, L> {
        let result = unsafe { ffi::lua_getmetatable(self.variable.use_lua(), -1) };

        if result == 0 {
            unsafe {
                ffi::lua_newtable(self.variable.use_lua());
                ffi::lua_setmetatable(self.variable.use_lua(), -2);
                let r = ffi::lua_getmetatable(self.variable.use_lua(), -1);
                assert!(r != 0);
            }
        }

        // note: it would be cleaner to create another table, but cannot manage to make it compile
        self.variable.size += 1;
        self
    }
}

impl<'a, 'b, L: HasLua, K: CopyRead<LuaTableIterator<'a, 'b, L>>, V: CopyRead<LuaTableIterator<'a, 'b, L>>>
    Iterator<Option<(K, V)>> for LuaTableIterator<'a, 'b, L>
{
    fn next(&mut self)
        -> Option<Option<(K,V)>>
    {
        if self.finished {
            return None
        }

        // this call pushes the next key and value on the stack
        if unsafe { ffi::lua_next(self.table.use_lua(), -2) } == 0 {
            self.finished = true;
            return None
        }

        let key = CopyRead::read_from_lua(self, -2);
        let value = CopyRead::read_from_lua(self, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { ffi::lua_pop(self.table.use_lua(), 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

#[unsafe_destructor]
impl<'a, 'b, L: HasLua> Drop for LuaTableIterator<'a, 'b, L> {
    fn drop(&mut self) {
        if !self.finished {
            unsafe { ffi::lua_pop(self.table.variable.use_lua(), 1) }
        }
    }
}
<|endoftext|>


<commit_before>use crate::*;

/*----------------------------------------------------------------------------*/
// Decrypt Single-character XOR

pub fn single_char_xor(v: &Vec<u8>) -> (u8, f32, Vec<u8>) {
    single_char_xors(&v).swap_remove(0)
}

pub fn single_char_xors(v: &Vec<u8>) -> Vec<(u8, f32, Vec<u8>)> {
    let mut scored: Vec<(u8, f32, Vec<u8>)> = reference::ascii_chars()
        .into_iter()
        .map(|c| find_score(c, v))
        .collect();

    scored.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());

    scored
}

fn find_score(c: u8, msg: &Vec<u8>) -> (u8, f32, Vec<u8>) {
    let v = vec![c].repeat(msg.len());
    let xored = vector::xor(&v, msg);

    (c, metrics::score_alphabetic(&xored), xored)
}

/*----------------------------------------------------------------------------*/
// Decrypt Multi-character XOR (Vignere Cipher)

pub fn multi_char_xor(v: &Vec<u8>, key_low: u8, key_high: u8) -> Vec<u8> {
    let key_size = find_key_size(v, key_low, key_high);
    let transposed: Vec<Vec<u8>> = vector::transpose(
        v.chunks_exact(key_size as usize)
            .map(|row| row.to_vec())
            .collect(),
    );

    let key: Vec<u8> = transposed
        .iter()
        .map(|row| single_char_xor(row))
        .map(|(c, _, _)| c)
        .collect();
    let key_ = key.repeat(v.len() / (key_size as usize) + 1);

    vector::xor(v, &key_)
}

fn find_key_size(v: &Vec<u8>, low: u8, high: u8) -> u8 {
    let (_, key_size) = find_key_sizes(v, low, high).swap_remove(0);
    key_size
}

fn find_key_sizes(v: &Vec<u8>, low: u8, high: u8) -> Vec<(f32, u8)> {
    let mut pairs = Vec::new();
    for guess in low..=high {
        if v.len() > (guess * 4).into() {
            pairs.push((score_key(guess, v), guess));
        }
    }
    pairs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
    pairs
}

// score key size as average Hamming distance normalized by key size
fn score_key(size: u8, v: &Vec<u8>) -> f32 {
    let n = size as usize;
    let m1 = &v[0..n].to_vec();
    let m2 = &v[n..2 * n].to_vec();
    let m3 = &v[2 * n..3 * n].to_vec();
    let m4 = &v[3 * n..4 * n].to_vec();

    let sum = metrics::hamming_distance(m1, m2)
        + metrics::hamming_distance(m1, m3)
        + metrics::hamming_distance(m1, m4)
        + metrics::hamming_distance(m2, m3)
        + metrics::hamming_distance(m2, m4)
        + metrics::hamming_distance(m3, m4);

    (sum as f32) / (6.0 * (size as f32))
}
<commit_msg>refactor<commit_after>use crate::*;

/*----------------------------------------------------------------------------*/
// Decrypt Single-character XOR

pub fn single_char_xor(v: &Vec<u8>) -> (u8, f32, Vec<u8>) {
    single_char_xors(&v).swap_remove(0)
}

pub fn single_char_xors(v: &Vec<u8>) -> Vec<(u8, f32, Vec<u8>)> {
    let mut scored: Vec<(u8, f32, Vec<u8>)> = reference::ascii_chars()
        .into_iter()
        .map(|c| find_score(c, v))
        .collect();

    scored.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());

    scored
}

fn find_score(c: u8, msg: &Vec<u8>) -> (u8, f32, Vec<u8>) {
    let v = vec![c].repeat(msg.len());
    let xored = vector::xor(&v, msg);

    (c, metrics::score_alphabetic(&xored), xored)
}

/*----------------------------------------------------------------------------*/
// Decrypt Multi-character XOR (Vignere Cipher)

pub fn multi_char_xor(v: &Vec<u8>, key_low: u8, key_high: u8) -> Vec<u8> {
    let key_size = find_key_size(v, key_low, key_high);
    let transposed: Vec<Vec<u8>> = vector::transpose(to_blocks(v, key_size as usize));

    let key: Vec<u8> = transposed
        .iter()
        .map(|row| single_char_xor(row))
        .map(|(c, _, _)| c)
        .collect();
    let key_ = key.repeat(v.len() / (key_size as usize) + 1);

    vector::xor(v, &key_)
}

fn find_key_size(v: &Vec<u8>, low: u8, high: u8) -> u8 {
    let (_, key_size) = find_key_sizes(v, low, high).swap_remove(0);
    key_size
}

fn find_key_sizes(v: &Vec<u8>, low: u8, high: u8) -> Vec<(f32, u8)> {
    let mut pairs = Vec::new();
    for guess in low..=high {
        if v.len() > (guess * 4).into() {
            pairs.push((score_key(guess, v), guess));
        }
    }
    pairs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
    pairs
}

// score key size as average Hamming distance normalized by key size
fn score_key(size: u8, v: &Vec<u8>) -> f32 {
    let blocks = to_blocks(v, size as usize);
    let pairs = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)];
    let sum: u32 = pairs
        .into_iter()
        .map(|(i1, i2)| metrics::hamming_distance(&blocks[i1], &blocks[i2]))
        .sum();

    (sum as f32) / (size as f32) / (pairs.len() as f32)
}

fn to_blocks(v: &Vec<u8>, size: usize) -> Vec<Vec<u8>> {
    let blocks = v.chunks_exact(size).map(|block| block.to_vec()).collect();
    blocks
}
<|endoftext|>


<commit_before>use std::iter;
use std::iter::FromIterator;

const CUTOFF: usize = 5;

pub struct SuffixArray {
    text: Vec<char>,
    index: Vec<usize>,
    n: usize
}

impl SuffixArray {
    pub fn new(s: &str) -> SuffixArray {
        let n = s.len();
        let text = s.chars().chain(iter::once(0 as char)).collect::<Vec<char>>();
        let index = (0..n).collect();

        let mut sa = SuffixArray {
            text: text,
            index: index,
            n: n
        };
        sa.sort(0, n-1, 0);
        sa
    }

    // 3-way string quicksort
    fn sort(&mut self, lo: usize, hi: usize, d: usize) {
        // cutoff
        if hi <= lo + CUTOFF {
            self.insertion(lo, hi, d);
            return ;
        }

        let mut lt = lo;
        let mut gt = hi;
        let v = self.text[self.index[lo] + d];
        let mut i = lo + 1;
        while i <= gt {
            let t = self.text[self.index[i] + d];
            if t < v {
                self.index.swap(lt, i);
                lt += 1;
                i += 1;
            } else if t > v {
                self.index.swap(i, gt);
                gt -= 1;
            } else {
                i += 1;
            }
        }

        self.sort(lo, lt-1, d);
        if v > 0 as char {
            self.sort(lt, gt, d+1);
        }
        self.sort(gt+1, hi, d);
    }

    fn insertion(&mut self, lo: usize, hi: usize, d: usize) {
        for i in lo .. hi+1 {
            for j in (0 .. i+1).rev() {
                if !(j > lo && self.less(self.index[j], self.index[j-1], d)) {
                    break;
                }
                self.index.swap(j, j-1);
            }
        }
    }

    fn less(&self, i: usize, j: usize, d: usize) -> bool {
        if i == j {
            return false;
        }
        let mut i = i + d;
        let mut j = j + d;
        while i < self.n && j < self.n {
            if self.text[i] < self.text[j] {
                return true;
            }
            if self.text[i] > self.text[j] {
                return false;
            }
            i += 1;
            j += 1;
        }
        return i > j;
    }

    pub fn length(&self) -> usize {
        self.n
    }

    pub fn index(&self, i: usize) -> usize {
        self.index[i]
    }

    // length of the longest common prefix
    pub fn lcp(&self, i: usize) -> usize {
        if i < 1 || i >= self.n {
            panic!("index out of bounds");
        }
        self.lcp_helper(self.index[i], self.index[i-1])
    }

    fn lcp_helper(&self, mut i: usize, mut j: usize) -> usize {
        let mut length = 0;
        while i < self.n && j < self.n {
            if self.text[i] != self.text[j] {
                return length;
            }
            i += 1;
            j += 1;
            length += 1;
        }
        length
    }

    pub fn select(&self, i: usize) -> String {
        if i >= self.n {
            panic!("index out of bounds");
        }
        FromIterator::from_iter(self.text[self.index[i] .. self.n].iter().map(|c| *c))
    }

    pub fn rank(&self, query: &str) -> usize {
        let mut lo = 0;
        let mut hi = self.n - 1;
        while lo <= hi {
            let mid = lo + (hi-lo)/2;
            let cmp = self.compare(query, self.index[mid]);
            if cmp <0 {
                hi = mid - 1;
            } else if cmp > 0 {
                lo = mid + 1;
            } else {
                return mid;
            }
        }
        return lo;
    }

    fn compare(&self, query: &str, mut i: usize) -> i32 {
        let qlen = query.len();
        let mut j = 0;
        while i < self.n && j <= qlen {
            if query.char_at(j) != self.text[i] {
                return query.char_at(j) as i32 - self.text[i] as i32;
            }
            i += 1;
            j += 1;
        }
        if i < self.n { return -1; }
        if j < qlen { return 1; }
        return 0;
    }
}

#[test]
fn test_suffix_array() {
    let s = "banana";
    // suffix 0 => 5 a
    // suffix 1 => 3 ana
    // suffix 2 => 1 anana
    // suffix 3 => 0 banana
    // suffix 4 => 4 na
    // suffix 5 => 2 nana
    let suffix = SuffixArray::new(s);

    assert_eq!(suffix.select(0), "a");
    assert_eq!(suffix.index(0), 5);

    assert_eq!(suffix.select(4), "na");
    // "anz" should be in 3rd place
    assert_eq!(suffix.rank("anz"), 3);
}
<commit_msg>suffix_arrays: store original str ref in SuffixArray<commit_after>use std::iter;

const CUTOFF: usize = 5;

// TODO: add a generic SuffixArray

/// A data type that computes the suffix array of a string using 3-way
/// radix quicksort.
pub struct SuffixArray<'a> {
    text: Vec<char>,
    index: Vec<usize>,
    s: &'a str,
    n: usize,
}

impl<'a> SuffixArray<'a> {
    pub fn new<'b>(s: &'a str) -> SuffixArray<'a> {
        let n = s.len();
        let text = s.chars().chain(iter::once(0 as char)).collect::<Vec<char>>();
        let index = (0..n).collect();

        let mut sa = SuffixArray {
            text: text,
            index: index,
            n: n,
            s: s
        };
        sa.sort(0, n-1, 0);
        sa
    }

    // 3-way string quicksort
    fn sort(&mut self, lo: usize, hi: usize, d: usize) {
        // cutoff
        if hi <= lo + CUTOFF {
            self.insertion(lo, hi, d);
            return ;
        }

        let mut lt = lo;
        let mut gt = hi;
        let v = self.text[self.index[lo] + d];
        let mut i = lo + 1;
        while i <= gt {
            let t = self.text[self.index[i] + d];
            if t < v {
                self.index.swap(lt, i);
                lt += 1;
                i += 1;
            } else if t > v {
                self.index.swap(i, gt);
                gt -= 1;
            } else {
                i += 1;
            }
        }

        self.sort(lo, lt-1, d);
        if v > 0 as char {
            self.sort(lt, gt, d+1);
        }
        self.sort(gt+1, hi, d);
    }

    fn insertion(&mut self, lo: usize, hi: usize, d: usize) {
        for i in lo .. hi+1 {
            for j in (0 .. i+1).rev() {
                if !(j > lo && self.less(self.index[j], self.index[j-1], d)) {
                    break;
                }
                self.index.swap(j, j-1);
            }
        }
    }

    fn less(&self, i: usize, j: usize, d: usize) -> bool {
        if i == j {
            return false;
        }
        let mut i = i + d;
        let mut j = j + d;
        while i < self.n && j < self.n {
            if self.text[i] < self.text[j] {
                return true;
            }
            if self.text[i] > self.text[j] {
                return false;
            }
            i += 1;
            j += 1;
        }
        return i > j;
    }

    pub fn length(&self) -> usize {
        self.n
    }

    pub fn index(&self, i: usize) -> usize {
        self.index[i]
    }

    // length of the longest common prefix
    pub fn lcp(&self, i: usize) -> usize {
        if i < 1 || i >= self.n {
            panic!("index out of bounds");
        }
        self.lcp_helper(self.index[i], self.index[i-1])
    }

    fn lcp_helper(&self, mut i: usize, mut j: usize) -> usize {
        let mut length = 0;
        while i < self.n && j < self.n {
            if self.text[i] != self.text[j] {
                return length;
            }
            i += 1;
            j += 1;
            length += 1;
        }
        length
    }

    pub fn select(&self, i: usize) -> &'a str {
        if i >= self.n {
            panic!("index out of bounds");
        }
        &self.s[self.index[i]..]
    }

    pub fn rank(&self, query: &str) -> usize {
        let mut lo = 0;
        let mut hi = self.n - 1;
        while lo <= hi {
            let mid = lo + (hi-lo)/2;
            let cmp = self.compare(query, self.index[mid]);
            if cmp <0 {
                hi = mid - 1;
            } else if cmp > 0 {
                lo = mid + 1;
            } else {
                return mid;
            }
        }
        return lo;
    }

    fn compare(&self, query: &str, mut i: usize) -> i32 {
        let qlen = query.len();
        let mut j = 0;
        while i < self.n && j <= qlen {
            if query.char_at(j) != self.text[i] {
                return query.char_at(j) as i32 - self.text[i] as i32;
            }
            i += 1;
            j += 1;
        }
        if i < self.n { return -1; }
        if j < qlen { return 1; }
        return 0;
    }
}

#[test]
fn test_suffix_array() {
    let s = "banana";
    // suffix 0 => 5 a
    // suffix 1 => 3 ana
    // suffix 2 => 1 anana
    // suffix 3 => 0 banana
    // suffix 4 => 4 na
    // suffix 5 => 2 nana
    let suffix = SuffixArray::new(s);

    assert_eq!(suffix.select(0), "a");
    assert_eq!(suffix.index(0), 5);

    assert_eq!(suffix.select(4), "na");
    // "anz" should be in 3rd place
    assert_eq!(suffix.rank("anz"), 3);
}
<|endoftext|>


<commit_before>#![feature(custom_derive)]
#![feature(plugin)]
#![plugin(serde_macros)]
#![feature(question_mark)]

extern crate exonum;
extern crate timestamping;
extern crate env_logger;
extern crate clap;
extern crate toml;
extern crate serde;

use std::path::Path;
use std::fs;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;

use clap::{Arg, App, SubCommand};
use toml::Encoder;
use serde::Serialize;

use exonum::node::{Node, Configuration};
use exonum::events::{NetworkConfiguration, EventsConfiguration};
use exonum::crypto::{gen_keypair_from_seed, Seed, PublicKey, SecretKey};
use exonum::storage::{MemoryDB, LevelDB, LevelDBOptions};

use timestamping::TimestampingBlockchain;

#[derive(Clone, Debug, Serialize, Deserialize)]
struct KeyPair {
    public_key: PublicKey,
    secret_key: SecretKey,
    address: ::std::net::SocketAddr,
}

#[derive(Debug, Serialize, Deserialize)]
struct TestNetConfiguration {
    validators: Vec<KeyPair>,
    round_timeout: u32,
    status_timeout: u32,
    peers_timeout: u32,
    max_incoming_connections: usize,
    max_outgoing_connections: usize,
    db_path: Option<String>,
}

impl TestNetConfiguration {
    fn from_file(path: &Path) -> Result<TestNetConfiguration, Box<Error>> {
        let mut file = File::open(path)?;
        let mut toml = String::new();
        file.read_to_string(&mut toml)?;
        let cfg = toml::decode_str(&toml);

        // match cfg {
        //     Some(value) => Ok(value),
        //     None => Err(format!("Unable to decode toml file: {:?}", path))
        // }

        return Ok(cfg.unwrap());
    }

    fn save_to_file(&self, path: &Path) -> Result<(), Box<Error>> {
        if let Some(dir) = path.parent() {
            fs::create_dir_all(dir).unwrap();
        }

        let mut e = Encoder::new();
        self.serialize(&mut e).unwrap();
        let mut file = File::create(path).unwrap();
        file.write_all(toml::encode_str(&e.toml).as_bytes())?;

        Ok(())
    }

    fn gen(validators_count: u8) -> TestNetConfiguration {
        let mut pairs = Vec::new();
        for i in 0..validators_count {
            let keys = gen_keypair_from_seed(&Seed::from_slice(&vec![i; 32]).unwrap());
            let addr = format!("127.0.0.1:{}", 7000 + i as u32).parse().unwrap();
            let pair = KeyPair {
                public_key: keys.0.clone(),
                secret_key: keys.1.clone(),
                address: addr,
            };
            pairs.push(pair);
        }

        TestNetConfiguration {
            validators: pairs,
            round_timeout: 1000,
            status_timeout: 5000,
            peers_timeout: 10000,
            max_incoming_connections: validators_count as usize,
            max_outgoing_connections: validators_count as usize,
            db_path: None,
        }
    }

    fn to_node_configuration(&self, idx: usize) -> Configuration {
        let validator = self.validators[idx].clone();
        let validators: Vec<_> = self.validators
            .iter()
            .map(|v| v.public_key)
            .collect();
        let addresses: Vec<_> = self.validators
            .iter()
            .map(|v| v.address)
            .collect();

        Configuration {
            public_key: validator.public_key,
            secret_key: validator.secret_key,
            round_timeout: self.round_timeout,
            status_timeout: self.status_timeout,
            peers_timeout: self.peers_timeout,
            network: NetworkConfiguration {
                listen_address: validator.address,
                max_incoming_connections: self.max_incoming_connections,
                max_outgoing_connections: self.max_outgoing_connections,
            },
            events: EventsConfiguration::new(),
            peer_discovery: addresses,
            validators: validators,
        }
    }
}

fn main() {
    ::std::env::set_var("RUST_LOG", "exonum=info");
    env_logger::init().unwrap();

    let app = App::new("TestNet node")
        .version("0.1")
        .author("Aleksey S. <aleksei.sidorov@xdev.re>")
        .about("Test network node")
        .arg(Arg::with_name("LEVELDB_PATH")
            .short("d")
            .long("leveldb-path")
            .value_name("LEVELDB_PATH")
            .help("Use leveldb database with the given path")
            .takes_value(true))
        .arg(Arg::with_name("CONFIG")
            .short("c")
            .long("config")
            .value_name("CONFIG_PATH")
            .help("Sets a testnet config file")
            .required(true)
            .takes_value(true))
        .subcommand(SubCommand::with_name("generate")
            .about("Generates default configuration file")
            .version("0.1")
            .author("Aleksey S. <aleksei.sidorov@xdev.re>")
            .arg(Arg::with_name("COUNT")
                .help("Validators count")
                .required(true)
                .index(1)))
        .subcommand(SubCommand::with_name("run")
            .about("Run test node with the given validator id")
            .version("0.1")
            .author("Aleksey S. <aleksei.sidorov@xdev.re>")
            .arg(Arg::with_name("VALIDATOR")
                .help("Sets a validator id")
                .required(true)
                .index(1)));

    let matches = app.get_matches();
    let path = Path::new(matches.value_of("CONFIG").unwrap());
    let db_path = matches.value_of("LEVELDB_PATH").map(|x| x.to_owned());
    match matches.subcommand() {
        ("generate", Some(matches)) => {
            let count: u8 = matches.value_of("COUNT").unwrap().parse().unwrap();
            let mut cfg = TestNetConfiguration::gen(count);
            cfg.db_path = db_path;

            cfg.save_to_file(&path).unwrap();
            println!("The configuration was successfully written to file {:?}",
                     path);
        }
        ("run", Some(matches)) => {
            let idx: usize = matches.value_of("VALIDATOR").unwrap().parse().unwrap();
            let cfg = TestNetConfiguration::from_file(path).unwrap();

            let node_cfg = cfg.to_node_configuration(idx);
            match cfg.db_path {
                Some(db_path) => {
                    let mut options = LevelDBOptions::new();
                    options.create_if_missing = true;
                    let leveldb = LevelDB::new(&Path::new(&db_path), options).unwrap();

                    let blockchain = TimestampingBlockchain { db: leveldb };
                    Node::with_config(blockchain, node_cfg).run();
                }
                None => {
                    let blockchain = TimestampingBlockchain { db: MemoryDB::new() };
                    Node::with_config(blockchain, node_cfg).run();
                }
            };
        }
        _ => {
            unreachable!("Wrong subcommand");
        }
    }
}
<commit_msg>Add known_peer option to emulate peers discovery<commit_after>#![feature(custom_derive)]
#![feature(plugin)]
#![plugin(serde_macros)]
#![feature(question_mark)]

extern crate exonum;
extern crate timestamping;
extern crate env_logger;
extern crate clap;
extern crate toml;
extern crate serde;

use std::path::Path;
use std::fs;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;

use clap::{Arg, App, SubCommand};
use toml::Encoder;
use serde::Serialize;

use exonum::node::{Node, Configuration};
use exonum::events::{NetworkConfiguration, EventsConfiguration};
use exonum::crypto::{gen_keypair_from_seed, Seed, PublicKey, SecretKey};
use exonum::storage::{MemoryDB, LevelDB, LevelDBOptions};

use timestamping::TimestampingBlockchain;

#[derive(Clone, Debug, Serialize, Deserialize)]
struct KeyPair {
    public_key: PublicKey,
    secret_key: SecretKey,
    address: ::std::net::SocketAddr,
}

#[derive(Debug, Serialize, Deserialize)]
struct TestNetConfiguration {
    validators: Vec<KeyPair>,
    round_timeout: u32,
    status_timeout: u32,
    peers_timeout: u32,
    max_incoming_connections: usize,
    max_outgoing_connections: usize,
}

impl TestNetConfiguration {
    fn from_file(path: &Path) -> Result<TestNetConfiguration, Box<Error>> {
        let mut file = File::open(path)?;
        let mut toml = String::new();
        file.read_to_string(&mut toml)?;
        let cfg = toml::decode_str(&toml);

        // match cfg {
        //     Some(value) => Ok(value),
        //     None => Err(format!("Unable to decode toml file: {:?}", path))
        // }

        return Ok(cfg.unwrap());
    }

    fn save_to_file(&self, path: &Path) -> Result<(), Box<Error>> {
        if let Some(dir) = path.parent() {
            fs::create_dir_all(dir).unwrap();
        }

        let mut e = Encoder::new();
        self.serialize(&mut e).unwrap();
        let mut file = File::create(path).unwrap();
        file.write_all(toml::encode_str(&e.toml).as_bytes())?;

        Ok(())
    }

    fn gen(validators_count: u8) -> TestNetConfiguration {
        let mut pairs = Vec::new();
        for i in 0..validators_count {
            let keys = gen_keypair_from_seed(&Seed::from_slice(&vec![i; 32]).unwrap());
            let addr = format!("127.0.0.1:{}", 7000 + i as u32).parse().unwrap();
            let pair = KeyPair {
                public_key: keys.0.clone(),
                secret_key: keys.1.clone(),
                address: addr,
            };
            pairs.push(pair);
        }

        TestNetConfiguration {
            validators: pairs,
            round_timeout: 1000,
            status_timeout: 5000,
            peers_timeout: 10000,
            max_incoming_connections: validators_count as usize,
            max_outgoing_connections: validators_count as usize,
        }
    }

    fn to_node_configuration(&self, idx: usize, known_peers: Vec<::std::net::SocketAddr>) -> Configuration {
        let validator = self.validators[idx].clone();
        let validators: Vec<_> = self.validators
            .iter()
            .map(|v| v.public_key)
            .collect();

        Configuration {
            public_key: validator.public_key,
            secret_key: validator.secret_key,
            round_timeout: self.round_timeout,
            status_timeout: self.status_timeout,
            peers_timeout: self.peers_timeout,
            network: NetworkConfiguration {
                listen_address: validator.address,
                max_incoming_connections: self.max_incoming_connections,
                max_outgoing_connections: self.max_outgoing_connections,
            },
            events: EventsConfiguration::new(),
            peer_discovery: known_peers,
            validators: validators,
        }
    }
}

fn main() {
    ::std::env::set_var("RUST_LOG", "exonum=info");
    env_logger::init().unwrap();

    let app = App::new("TestNet node")
        .version("0.1")
        .author("Aleksey S. <aleksei.sidorov@xdev.re>")
        .about("Test network node")
        .arg(Arg::with_name("CONFIG")
            .short("c")
            .long("config")
            .value_name("CONFIG_PATH")
            .help("Sets a testnet config file")
            .required(true)
            .takes_value(true))
        .subcommand(SubCommand::with_name("generate")
            .about("Generates default configuration file")
            .version("0.1")
            .author("Aleksey S. <aleksei.sidorov@xdev.re>")
            .arg(Arg::with_name("COUNT")
                .help("Validators count")
                .required(true)
                .index(1)))
        .subcommand(SubCommand::with_name("run")
            .about("Run test node with the given validator id")
            .version("0.1")
            .author("Aleksey S. <aleksei.sidorov@xdev.re>")
            .arg(Arg::with_name("LEVELDB_PATH")
                .short("d")
                .long("leveldb-path")
                .value_name("LEVELDB_PATH")
                .help("Use leveldb database with the given path")
                .takes_value(true))
            .arg(Arg::with_name("PEERS")
                .short("p")
                .long("known-peers")
                .value_name("PEERS")
                .help("Somma separated list of known validator ids")
                .takes_value(true))
            .arg(Arg::with_name("VALIDATOR")
                .help("Sets a validator id")
                .required(true)
                .index(1)));

    let matches = app.get_matches();
    let path = Path::new(matches.value_of("CONFIG").unwrap());
    match matches.subcommand() {
        ("generate", Some(matches)) => {
            let count: u8 = matches.value_of("COUNT").unwrap().parse().unwrap();
            let cfg = TestNetConfiguration::gen(count);
            cfg.save_to_file(&path).unwrap();
            println!("The configuration was successfully written to file {:?}",
                     path);
        }
        ("run", Some(matches)) => {
            let cfg = TestNetConfiguration::from_file(path).unwrap();
            let idx: usize = matches.value_of("VALIDATOR").unwrap().parse().unwrap();
            let peers = match matches.value_of("PEERS") {
                Some(string) => {
                    string.split(" ")
                        .map(|x| -> usize { x.parse().unwrap() })
                        .map(|x| cfg.validators[x].address)
                        .collect()
                }
                None => {
                    cfg.validators
                        .iter()
                        .map(|v| v.address)
                        .collect()
                }
            };
            println!("Known peers is {:#?}", peers);
            let node_cfg = cfg.to_node_configuration(idx, peers);
            let db_path = matches.value_of("LEVELDB_PATH").map(|x| x.to_owned());

            match db_path {
                Some(db_path) => {
                    println!("Using levedb storage with path: {}", db_path);
                    let mut options = LevelDBOptions::new();
                    options.create_if_missing = true;
                    let leveldb = LevelDB::new(&Path::new(&db_path), options).unwrap();

                    let blockchain = TimestampingBlockchain { db: leveldb };
                    Node::with_config(blockchain, node_cfg).run();
                }
                None => {
                    println!("Using memorydb storage");
                    let blockchain = TimestampingBlockchain { db: MemoryDB::new() };
                    Node::with_config(blockchain, node_cfg).run();
                }
            };
        }
        _ => {
            unreachable!("Wrong subcommand");
        }
    }
}
<|endoftext|>