<commit_before>use mio::Interest;

#[test]
fn is_tests() {
    assert!(Interest::READABLE.is_readable());
    assert!(!Interest::READABLE.is_writable());
    assert!(!Interest::WRITABLE.is_readable());
    assert!(Interest::WRITABLE.is_writable());
    assert!(!Interest::WRITABLE.is_aio());
    assert!(!Interest::WRITABLE.is_lio());
}

#[test]
fn bit_or() {
    let interests = Interest::READABLE | Interest::WRITABLE;
    assert!(interests.is_readable());
    assert!(interests.is_writable());
}

#[test]
fn fmt_debug() {
    assert_eq!(format!("{:?}", Interest::READABLE), "READABLE");
    assert_eq!(format!("{:?}", Interest::WRITABLE), "WRITABLE");
    assert_eq!(
        format!("{:?}", Interest::READABLE | Interest::WRITABLE),
        "READABLE | WRITABLE"
    );
    #[cfg(any(
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "ios",
        target_os = "macos"
    ))]
    {
        assert_eq!(format!("{:?}", Interest::AIO), "AIO");
    }
    #[cfg(any(target_os = "freebsd"))]
    {
        assert_eq!(format!("{:?}", Interest::LIO), "LIO");
    }
}
<commit_msg>added tests for Interest::add<commit_after>use mio::Interest;

#[test]
fn is_tests() {
    assert!(Interest::READABLE.is_readable());
    assert!(!Interest::READABLE.is_writable());
    assert!(!Interest::WRITABLE.is_readable());
    assert!(Interest::WRITABLE.is_writable());
    assert!(!Interest::WRITABLE.is_aio());
    assert!(!Interest::WRITABLE.is_lio());
}

#[test]
fn bit_or() {
    let interests = Interest::READABLE | Interest::WRITABLE;
    assert!(interests.is_readable());
    assert!(interests.is_writable());
}

#[test]
fn fmt_debug() {
    assert_eq!(format!("{:?}", Interest::READABLE), "READABLE");
    assert_eq!(format!("{:?}", Interest::WRITABLE), "WRITABLE");
    assert_eq!(
        format!("{:?}", Interest::READABLE | Interest::WRITABLE),
        "READABLE | WRITABLE"
    );
    #[cfg(any(
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "ios",
        target_os = "macos"
    ))]
    {
        assert_eq!(format!("{:?}", Interest::AIO), "AIO");
    }
    #[cfg(any(target_os = "freebsd"))]
    {
        assert_eq!(format!("{:?}", Interest::LIO), "LIO");
    }
}

#[test]
fn add() {
    let interest: Interest = Interest::READABLE.add(Interest::WRITABLE);

    assert!(interest.is_readable());
    assert!(interest.is_writable());
}
<|endoftext|>


<commit_before>//! Miscellaneous helper traits, enums, and structs for models.

use super::prelude::*;
use internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
            Channel::Category(_) => panic!("Categories can't be mentioned"),
        }
    }
}

impl Mentionable for CurrentUser {
    fn mention(&self) -> String {
        format!("<@{}>", self.id.0)
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

impl Mentionable for GuildChannel {
    fn mention(&self) -> String { format!("<#{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {
    fn description(&self) -> &str {
        use self::UserParseError::*;

        match *self {
            InvalidUsername => "invalid username",
            Rest(_) => "could not fetch",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for User {
    type Err = UserParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_username(s) {
            Some(x) => UserId(x as u64)
                .get()
                .map_err(|e| UserParseError::Rest(Box::new(e))),
            _ => Err(UserParseError::InvalidUsername),
        }
    }
}

macro_rules! impl_from_str {
    (id: $($id:tt, $err:ident;)*) => {
        $(
            #[cfg(all(feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                InvalidFormat,
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl StdError for $err {
                fn description(&self) -> &str {
                    use self::$err::*;

                    match *self {
                        InvalidFormat => "invalid id format",
                    }
                }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl FromStr for $id {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    Ok(match utils::parse_username(s) {
                        Some(id) => $id(id),
                        None => s.parse::<u64>().map($id).map_err(|_| $err::InvalidFormat)?,
                    })
                }
            }
        )*
    };

    (struct: $($struct:ty, $id:tt, $err:ident, $invalid_variant:tt, $parse_fn:ident, $desc:expr;)*) => {
        $(
            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                NotPresentInCache,
                $invalid_variant,
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl StdError for $err {
                fn description(&self) -> &str {
                    use self::$err::*;

                    match *self {
                        NotPresentInCache => "not present in cache",
                        $invalid_variant => $desc,
                    }
                }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl FromStr for $struct {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    match utils::$parse_fn(s) {
                        Some(x) => match $id(x).find() {
                            Some(user) => Ok(user),
                            _ => Err($err::NotPresentInCache),
                        },
                        _ => Err($err::$invalid_variant),
                    }
                }
            }
        )*
    };
}

impl_from_str! { id:
    UserId, UserIdParseError;
    RoleId, RoleIdParseError;
    ChannelId, ChannelIdParseError;
}

impl_from_str! { struct:
    Channel, ChannelId, ChannelParseError, InvalidChannel, parse_channel, "invalid channel";
    Role, RoleId, RoleParseError, InvalidRole, parse_role, "invalid role";
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AffectedComponent {
    pub name: String,
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
}
<commit_msg>Implement Mentionable for ChannelCategory<commit_after>//! Miscellaneous helper traits, enums, and structs for models.

use super::prelude::*;
use internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
            Channel::Category(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
        }
    }
}

impl Mentionable for ChannelCategory {
    fn mention(&self) -> String {
        format!("#{}", self.name)
    }
}

impl Mentionable for CurrentUser {
    fn mention(&self) -> String {
        format!("<@{}>", self.id.0)
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

impl Mentionable for GuildChannel {
    fn mention(&self) -> String { format!("<#{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {
    fn description(&self) -> &str {
        use self::UserParseError::*;

        match *self {
            InvalidUsername => "invalid username",
            Rest(_) => "could not fetch",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for User {
    type Err = UserParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_username(s) {
            Some(x) => UserId(x as u64)
                .get()
                .map_err(|e| UserParseError::Rest(Box::new(e))),
            _ => Err(UserParseError::InvalidUsername),
        }
    }
}

macro_rules! impl_from_str {
    (id: $($id:tt, $err:ident;)*) => {
        $(
            #[cfg(all(feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                InvalidFormat,
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl StdError for $err {
                fn description(&self) -> &str {
                    use self::$err::*;

                    match *self {
                        InvalidFormat => "invalid id format",
                    }
                }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl FromStr for $id {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    Ok(match utils::parse_username(s) {
                        Some(id) => $id(id),
                        None => s.parse::<u64>().map($id).map_err(|_| $err::InvalidFormat)?,
                    })
                }
            }
        )*
    };

    (struct: $($struct:ty, $id:tt, $err:ident, $invalid_variant:tt, $parse_fn:ident, $desc:expr;)*) => {
        $(
            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                NotPresentInCache,
                $invalid_variant,
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl StdError for $err {
                fn description(&self) -> &str {
                    use self::$err::*;

                    match *self {
                        NotPresentInCache => "not present in cache",
                        $invalid_variant => $desc,
                    }
                }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl FromStr for $struct {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    match utils::$parse_fn(s) {
                        Some(x) => match $id(x).find() {
                            Some(user) => Ok(user),
                            _ => Err($err::NotPresentInCache),
                        },
                        _ => Err($err::$invalid_variant),
                    }
                }
            }
        )*
    };
}

impl_from_str! { id:
    UserId, UserIdParseError;
    RoleId, RoleIdParseError;
    ChannelId, ChannelIdParseError;
}

impl_from_str! { struct:
    Channel, ChannelId, ChannelParseError, InvalidChannel, parse_channel, "invalid channel";
    Role, RoleId, RoleParseError, InvalidRole, parse_role, "invalid role";
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AffectedComponent {
    pub name: String,
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
}
<|endoftext|>


<commit_before>use runtime::Runtime;
use std::error::Error;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::fmt::Display;
use std::path::Path;
use std::result::Result;

use module::todo::TodoModule;

mod todo;

#[derive(Debug)]
pub struct ModuleError {
    desc: String,
}

impl ModuleError {
    fn mk(desc: &'static str) -> ModuleError {
        ModuleError {
            desc: desc.to_owned().to_string(),
        }
    }
}

impl Error for ModuleError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for ModuleError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "ModuleError: {}", self.description())
    }
}

pub type ModuleResult = Result<(), ModuleError>;

pub trait Module {

    fn new(rt : &Runtime) -> Self;
    fn callnames() -> &'static [&'static str];
    fn name(&self) -> &'static str;

    fn execute(&self, rt : &Runtime) -> ModuleResult;
    fn shutdown(&self, rt : &Runtime) -> ModuleResult;

}

pub mod file {

    use regex::Regex;

    pub struct ParserError {
        summary: String,
        parsertext: String,
        index: i32,
        explanation: Option<String>,
    }

    impl ParserError {
        fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
            ParserError {
                summary: String::from(sum),
                parsertext: text,
                index: idx,
                explanation: Some(String::from(expl)),
            }
        }

        fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
            ParserError {
                summary: String::from(sum),
                parsertext: text,
                index: idx,
                explanation: None
            }
        }
    }

    pub enum FileHeaderSpec {
        Null,
        Bool,
        Integer,
        UInteger,
        Float,
        Text,
        Key { name: String, value_type: Box<FileHeaderSpec> },
        Array { allowed_types: Box<Vec<FileHeaderSpec>> },
    }

    pub enum FileHeaderData {
        Null,
        Bool(bool),
        Integer(i64),
        UInteger(u64),
        Float(f64),
        Text(String),
        Key { name: String, value: Box<FileHeaderData> },
        Array { values: Box<Vec<FileHeaderData>> },
    }

    pub trait FileHeaderParser : Sized {
        fn new(spec: &FileHeaderSpec) -> Self;
        fn read(&self, string: &String) -> Result<FileHeaderData, ParserError>;
        fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
    }

    pub trait FileData : Sized {
        fn get_fulltext(&self) -> String;
        fn get_abbrev(&self) -> String;
    }

    pub trait FileDataParser : Sized {
        fn new() -> FileDataParser;
        fn read(&self, string: String) -> FileData;
        fn write(&self, data: &FileData) -> Result<String, ParserError>;
    }

    pub type HeaderDataTpl = (Option<String>, Option<String>);

    pub fn divide_text(text: String) -> Result<HeaderDataTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}
<commit_msg>FileHeaderParser::read() should get the string, not a ref to it<commit_after>use runtime::Runtime;
use std::error::Error;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::fmt::Display;
use std::path::Path;
use std::result::Result;

use module::todo::TodoModule;

mod todo;

#[derive(Debug)]
pub struct ModuleError {
    desc: String,
}

impl ModuleError {
    fn mk(desc: &'static str) -> ModuleError {
        ModuleError {
            desc: desc.to_owned().to_string(),
        }
    }
}

impl Error for ModuleError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for ModuleError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "ModuleError: {}", self.description())
    }
}

pub type ModuleResult = Result<(), ModuleError>;

pub trait Module {

    fn new(rt : &Runtime) -> Self;
    fn callnames() -> &'static [&'static str];
    fn name(&self) -> &'static str;

    fn execute(&self, rt : &Runtime) -> ModuleResult;
    fn shutdown(&self, rt : &Runtime) -> ModuleResult;

}

pub mod file {

    use regex::Regex;

    pub struct ParserError {
        summary: String,
        parsertext: String,
        index: i32,
        explanation: Option<String>,
    }

    impl ParserError {
        fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
            ParserError {
                summary: String::from(sum),
                parsertext: text,
                index: idx,
                explanation: Some(String::from(expl)),
            }
        }

        fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
            ParserError {
                summary: String::from(sum),
                parsertext: text,
                index: idx,
                explanation: None
            }
        }
    }

    pub enum FileHeaderSpec {
        Null,
        Bool,
        Integer,
        UInteger,
        Float,
        Text,
        Key { name: String, value_type: Box<FileHeaderSpec> },
        Array { allowed_types: Box<Vec<FileHeaderSpec>> },
    }

    pub enum FileHeaderData {
        Null,
        Bool(bool),
        Integer(i64),
        UInteger(u64),
        Float(f64),
        Text(String),
        Key { name: String, value: Box<FileHeaderData> },
        Array { values: Box<Vec<FileHeaderData>> },
    }

    pub trait FileHeaderParser : Sized {
        fn new(spec: &FileHeaderSpec) -> Self;
        fn read(&self, string: String) -> Result<FileHeaderData, ParserError>;
        fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
    }

    pub trait FileData : Sized {
        fn get_fulltext(&self) -> String;
        fn get_abbrev(&self) -> String;
    }

    pub trait FileDataParser : Sized {
        fn new() -> FileDataParser;
        fn read(&self, string: String) -> FileData;
        fn write(&self, data: &FileData) -> Result<String, ParserError>;
    }

    pub type HeaderDataTpl = (Option<String>, Option<String>);

    pub fn divide_text(text: String) -> Result<HeaderDataTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}
<|endoftext|>


<commit_before>use std::io::{FileAccess, FileMode, Open, Read, Truncate};
use std::io::{ReadWrite};
use std::io::{SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;
use std::io::Decorator;

static version: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
    hash_table_size : u64,
    key_size : u64,
    value_size : u64,
    num_hash_tables : u64,
    hash_tables : ~[u64],
    f : std::io::fs::File
}

enum OpenMode {
  ReadOnly,
  RW,
  RWCreate,
  RWReplace
}

fn kissdb_hash(b : &~[u8]) -> u64
{
    let mut hash : u64 = 5381;
    for &bx in b.iter() {
        hash = ((hash << 5) + hash) + (bx as u64);
    }
    return hash
}

fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
    ) -> Option<~ Kissdb>
{
    let (mode, access) : (FileMode, FileAccess) =
        match orig_mode {
            ReadOnly =>  (Open, Read), // rb
            RW => (Open, ReadWrite), // r+b
            RWCreate =>  (Open, ReadWrite), // r+b
            RWReplace => (Truncate, ReadWrite) // w+b
        };
    let mut f_ : Option<File>
        = std::io::fs::File::open_mode(path, mode, access);

    if f_.is_none() {
        match (orig_mode) {
            RWCreate =>
            f_ = std::io::fs::File::open_mode(path, Truncate, ReadWrite), // w+b
            _ => f_ = f_
        }
    };

    let mut f =
        match f_ {
            None => return None,
            Some (f) => f
        };
    let kissdb_header_size : u64 = ((size_of::<u64>() * 3) + 4) as u64;

    f.seek(0, SeekEnd);
    if (f.tell() < kissdb_header_size) {
        if hash_table_size > 0 && key_size > 0
            && value_size >0
        {
            f.seek(0, SeekSet);
            let tmp2 : [u8, ..4] = ['K' as u8, 'd' as u8, 'R' as u8, version];
            f.write(tmp2);
            f.write_le_u64(hash_table_size);
            f.write_le_u64(key_size);
            f.write_le_u64(value_size);
            f.flush();
        }
        else {
            fail!()
        }
    }
    else {
        f.seek(0, SeekSet);
        let mut tmp2 : [u8, ..4] = [0,0,0,0];
        if f.read(tmp2) != Some(4) { fail! (); }
        if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, version] {fail! ();}
        hash_table_size = f.read_le_u64();
        key_size = f.read_le_u64();
        value_size = f.read_le_u64();
    }

    let mut num_hash_tables = 0;

    let mut hash_tables : ~[u64] = std::vec::from_elem(0, 0 as u64);
    let mut h : Option<~[u64]>;

    // do we do realloc in rust? with append, apparently.
    while({h = f.read_one_hash_table(hash_table_size); h.is_some()})
    {
        let httmp = h.unwrap();
        hash_tables = std::vec::append(hash_tables, httmp);
        num_hash_tables = num_hash_tables + 1;
        if (httmp[hash_table_size] > 0) {
            f.seek(httmp[hash_table_size] as i64, SeekSet)
        }
        else {
            break;
        }
    }

    debug!("key_size = {:s}", key_size.to_str());

    return Some(~Kissdb {hash_table_size : hash_table_size,
                         key_size : key_size,
                         value_size : value_size,
                         num_hash_tables : num_hash_tables,
                         hash_tables : hash_tables,
                         f : f})
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
    fn write_one_hash_table(&mut self, &[u64]);
}

impl File2 for File {
    fn read_one_hash_table(&mut self,
                           hash_table_size : u64) -> Option<~[u64]> {
        let bs = (hash_table_size + 1) as uint * size_of::<u64>();
        let mut buf = std::vec::from_elem(bs, 0 as u8);
        let mut result = std::vec::from_elem((hash_table_size + 1) as uint, 0 as u64);
        match self.read(buf) {
            None => None,
            Some(buf_size) if buf_size == bs => {
                let mut br = std::io::mem::BufReader::new(buf);
                for i in range(0, hash_table_size + 1) {
                    result[i] = br.read_le_u64();
                }
                Some((result))
            },
            _ => None
        }
    }
    fn write_one_hash_table(&mut self,
                            ht : &[u64]) {
        for &x in ht.iter() {
            self.write_le_u64(x);
        }
    }
}

trait Kdb {
    fn kissdb_get(&mut self, &~[u8]) -> Option<~[u8]>;
    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool;
}

impl Kdb for Kissdb {
    fn kissdb_get(&mut self, key : &~[u8]) -> Option<~[u8]> {
        if key.len() != self.key_size as uint { return None }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let hash_tables = &self.hash_tables;
        for i in range(0, self.num_hash_tables) {
            let offset : i64 = hash_tables[i * (self.hash_table_size + 1) + hash] as i64;
            if (offset == 0) { return None }; // yeah, 0 is being special. never used normally.
            self.f.seek(offset as i64, SeekSet);

            let klen = self.key_size as uint;
            // isn't compare available?? read_bytes available
            let tmp = self.f.read_bytes(klen);

            if std::vec::bytes::memcmp(key, &tmp) == 0 {
                return Some(self.f.read_bytes(self.value_size as uint))
            }
        }
        return None
    }

    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool
    {
        if key.len() != self.key_size as uint { fail!() }
        if value.len() != self.value_size as uint { fail!() }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let mut lasthtoffset : u64 = ((size_of::<u64>() * 3) + 4) as u64;
        let mut htoffset = lasthtoffset;

        for i in range(0, self.num_hash_tables) {
            let offset : i64 = self.hash_tables[(self.hash_table_size + 1) * i + hash] as i64;
		    if (offset != 0) { // yes, 0 is treated special. 0 will never used normally
			    /* rewrite if already exists */
                self.f.seek(offset, SeekSet);

			    let klen = self.key_size as uint;
                let tmp = self.f.read_bytes(klen);
                if std::vec::bytes::memcmp(key, &tmp) == 0 {
                    self.f.write(value);
				    self.f.flush();
				    return true; /* success */
                }
                // put_no_match_next_hash_table:
        	    lasthtoffset = htoffset;
		        htoffset = self.hash_tables[(self.hash_table_size + 1) * i + self.hash_table_size];
                //cmp != , should be put_no_match_next_hash_table
		    } else {
			    /* add if an empty hash table slot is discovered */
                self.f.seek(0, SeekEnd);
	            let endoffset : u64 = self.f.tell();

                // debug!("endoffset = {:s}",endoffset.to_str());
                self.f.write(*key);
                self.f.write(value);

                self.f.seek(htoffset as i64 + (size_of::<u64>() as i64 * hash as i64), SeekSet);
                self.f.write_le_u64(endoffset);
			    self.hash_tables[(self.hash_table_size + 1) * i + hash] = endoffset;

			    self.f.flush();

			    return true; /* success */
		    }
	    }

	    /* if no existing slots, add a new page of hash table entries */
        debug!("add new page");
        self.f.seek(0, SeekEnd);
	    let endoffset = self.f.tell();

        let mut new_table : ~[u64] = std::vec::from_elem(self.hash_table_size as uint + 1, 0 as u64);
        let hash_table_size_bytes : u64 = size_of::<u64>() as u64 * (self.hash_table_size + 1);
        new_table[hash] = endoffset + hash_table_size_bytes; // where key, value are to be written
        self.f.write_one_hash_table(new_table);
        let longer = std::vec::append(self.hash_tables.clone(), new_table); // slow!!
        self.hash_tables = longer;

        debug!("writing at {:s}",self.f.tell().to_str());
        self.f.write(*key);
        self.f.write(value);

	    if (self.num_hash_tables > 0) {
            self.f.seek(lasthtoffset as i64 + (size_of::<u64>() as i64 * self.hash_table_size as i64), SeekSet);
            self.f.write_le_u64(endoffset);
            // mimick rereading
            self.hash_tables[((self.hash_table_size + 1) * (self.num_hash_tables - 1)) + self.hash_table_size] = endoffset;
	    }

        self.num_hash_tables = self.num_hash_tables + 1;
        self.f.flush();
	    return true; /* success */
    }

}

fn main()
{
    println("Opening new empty database test.db...");
    {
        let mut db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Adding and then re-getting 10000 64-byte values...");

        let mut v : [u8, .. 8] = [0,0,0,0,0,0,0,0];

        for i in range(0, 10000) {
            for j in range(0, 8) {
                v[j] = i as u8;
            }
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            db.kissdb_put(key.inner_ref(), v);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0, 8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }

        println("closing and re-opening database in read-only mode...");
    }

    {
        let mut db = kissdb_open(&Path::new("test.db"), ReadOnly, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
    }

	println("Iterator not implemented ...");

    println("All tests OK!");
}
<commit_msg>made indentation more consistent<commit_after>use std::io::{FileAccess, FileMode, Open, Read, Truncate};
use std::io::{ReadWrite};
use std::io::{SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;
use std::io::Decorator;

static version: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
    hash_table_size : u64,
    key_size : u64,
    value_size : u64,
    num_hash_tables : u64,
    hash_tables : ~[u64],
    f : std::io::fs::File
}

enum OpenMode {
    ReadOnly,
    RW,
    RWCreate,
    RWReplace
}

fn kissdb_hash(b : &~[u8]) -> u64
{
    let mut hash : u64 = 5381;
    for &bx in b.iter() {
        hash = ((hash << 5) + hash) + (bx as u64);
    }
    return hash
}

fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
        ) -> Option<~ Kissdb>
{
    let (mode, access) : (FileMode, FileAccess) =
        match orig_mode {
        ReadOnly =>  (Open, Read), // rb
        RW => (Open, ReadWrite), // r+b
        RWCreate =>  (Open, ReadWrite), // r+b
        RWReplace => (Truncate, ReadWrite) // w+b
    };
    let mut f_ : Option<File>
        = std::io::fs::File::open_mode(path, mode, access);

    if f_.is_none() {
        match (orig_mode) {
            RWCreate =>
                f_ = std::io::fs::File::open_mode(path, Truncate, ReadWrite), // w+b
            _ => f_ = f_
        }
    };

    let mut f =
        match f_ {
        None => return None,
        Some (f) => f
    };
    let kissdb_header_size : u64 = ((size_of::<u64>() * 3) + 4) as u64;

    f.seek(0, SeekEnd);
    if (f.tell() < kissdb_header_size) {
        if hash_table_size > 0 && key_size > 0
            && value_size >0
            {
            f.seek(0, SeekSet);
            let tmp2 : [u8, ..4] = ['K' as u8, 'd' as u8, 'R' as u8, version];
            f.write(tmp2);
            f.write_le_u64(hash_table_size);
            f.write_le_u64(key_size);
            f.write_le_u64(value_size);
            f.flush();
        }
            else {
            fail!()
        }
    }
        else {
        f.seek(0, SeekSet);
        let mut tmp2 : [u8, ..4] = [0,0,0,0];
        if f.read(tmp2) != Some(4) { fail! (); }
        if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, version] {fail! ();}
        hash_table_size = f.read_le_u64();
        key_size = f.read_le_u64();
        value_size = f.read_le_u64();
    }

    let mut num_hash_tables = 0;

    let mut hash_tables : ~[u64] = std::vec::from_elem(0, 0 as u64);
    let mut h : Option<~[u64]>;

    // do we do realloc in rust? with append, apparently.
    while({h = f.read_one_hash_table(hash_table_size); h.is_some()})
        {
        let httmp = h.unwrap();
        hash_tables = std::vec::append(hash_tables, httmp);
        num_hash_tables = num_hash_tables + 1;
        if (httmp[hash_table_size] > 0) {
            f.seek(httmp[hash_table_size] as i64, SeekSet)
        }
            else {
            break;
        }
    }

    debug!("key_size = {:s}", key_size.to_str());

    return Some(~Kissdb {hash_table_size : hash_table_size,
                         key_size : key_size,
                         value_size : value_size,
                         num_hash_tables : num_hash_tables,
                         hash_tables : hash_tables,
                         f : f})
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
    fn write_one_hash_table(&mut self, &[u64]);
}

impl File2 for File {
    fn read_one_hash_table(&mut self,
                           hash_table_size : u64) -> Option<~[u64]> {
        let bs = (hash_table_size + 1) as uint * size_of::<u64>();
        let mut buf = std::vec::from_elem(bs, 0 as u8);
        let mut result = std::vec::from_elem((hash_table_size + 1) as uint, 0 as u64);
        match self.read(buf) {
            None => None,
            Some(buf_size) if buf_size == bs => {
                let mut br = std::io::mem::BufReader::new(buf);
                for i in range(0, hash_table_size + 1) {
                    result[i] = br.read_le_u64();
                }
                Some((result))
            },
            _ => None
        }
    }
    fn write_one_hash_table(&mut self,
                            ht : &[u64]) {
        for &x in ht.iter() {
            self.write_le_u64(x);
        }
    }
}

trait Kdb {
    fn kissdb_get(&mut self, &~[u8]) -> Option<~[u8]>;
    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool;
}

impl Kdb for Kissdb {
    fn kissdb_get(&mut self, key : &~[u8]) -> Option<~[u8]> {
        if key.len() != self.key_size as uint { return None }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let hash_tables = &self.hash_tables;
        for i in range(0, self.num_hash_tables) {
            let offset : i64 = hash_tables[i * (self.hash_table_size + 1) + hash] as i64;
            if (offset == 0) { return None }; // yeah, 0 is being special. never used normally.
            self.f.seek(offset as i64, SeekSet);

            let klen = self.key_size as uint;
            // isn't compare available?? read_bytes available
            let tmp = self.f.read_bytes(klen);

            if std::vec::bytes::memcmp(key, &tmp) == 0 {
                return Some(self.f.read_bytes(self.value_size as uint))
            }
        }
        return None
    }

    fn kissdb_put(&mut self, key : &~[u8], value : &[u8]) -> bool
        {
        if key.len() != self.key_size as uint { fail!() }
        if value.len() != self.value_size as uint { fail!() }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let mut lasthtoffset : u64 = ((size_of::<u64>() * 3) + 4) as u64;
        let mut htoffset = lasthtoffset;

        for i in range(0, self.num_hash_tables) {
            let offset : i64 = self.hash_tables[(self.hash_table_size + 1) * i + hash] as i64;
            if (offset != 0) { // yes, 0 is treated special. 0 will never used normally
                /* rewrite if already exists */
                self.f.seek(offset, SeekSet);

                let klen = self.key_size as uint;
                let tmp = self.f.read_bytes(klen);
                if std::vec::bytes::memcmp(key, &tmp) == 0 {
                    self.f.write(value);
                    self.f.flush();
                    return true; /* success */
                }
                // put_no_match_next_hash_table:
                lasthtoffset = htoffset;
                htoffset = self.hash_tables[(self.hash_table_size + 1) * i + self.hash_table_size];
                //cmp != , should be put_no_match_next_hash_table
            } else {
                /* add if an empty hash table slot is discovered */
                self.f.seek(0, SeekEnd);
                let endoffset : u64 = self.f.tell();

                // debug!("endoffset = {:s}",endoffset.to_str());
                self.f.write(*key);
                self.f.write(value);

                self.f.seek(htoffset as i64 + (size_of::<u64>() as i64 * hash as i64), SeekSet);
                self.f.write_le_u64(endoffset);
                self.hash_tables[(self.hash_table_size + 1) * i + hash] = endoffset;

                self.f.flush();

                return true; /* success */
            }
        }

        /* if no existing slots, add a new page of hash table entries */
        debug!("add new page");
        self.f.seek(0, SeekEnd);
        let endoffset = self.f.tell();

        let mut new_table : ~[u64] = std::vec::from_elem(self.hash_table_size as uint + 1, 0 as u64);
        let hash_table_size_bytes : u64 = size_of::<u64>() as u64 * (self.hash_table_size + 1);
        new_table[hash] = endoffset + hash_table_size_bytes; // where key, value are to be written
        self.f.write_one_hash_table(new_table);
        let longer = std::vec::append(self.hash_tables.clone(), new_table); // slow!!
        self.hash_tables = longer;

        debug!("writing at {:s}",self.f.tell().to_str());
        self.f.write(*key);
        self.f.write(value);

        if (self.num_hash_tables > 0) {
            self.f.seek(lasthtoffset as i64 + (size_of::<u64>() as i64 * self.hash_table_size as i64), SeekSet);
            self.f.write_le_u64(endoffset);
            // mimick rereading
            self.hash_tables[((self.hash_table_size + 1) * (self.num_hash_tables - 1)) + self.hash_table_size] = endoffset;
        }

        self.num_hash_tables = self.num_hash_tables + 1;
        self.f.flush();
        return true; /* success */
    }

}

fn main()
{
    println("Opening new empty database test.db...");
    {
        let mut db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Adding and then re-getting 10000 64-byte values...");

        let mut v : [u8, .. 8] = [0,0,0,0,0,0,0,0];

        for i in range(0, 10000) {
            for j in range(0, 8) {
                v[j] = i as u8;
            }
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            db.kissdb_put(key.inner_ref(), v);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0, 8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }

        println("closing and re-opening database in read-only mode...");
    }

    {
        let mut db = kissdb_open(&Path::new("test.db"), ReadOnly, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = std::io::mem::MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner_ref()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
    }

    println("Iterator not implemented ...");

    println("All tests OK!");
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate log4rs;

extern crate iron;
extern crate logger;
extern crate router;
use iron::prelude::*;
use iron::status;
use logger::Logger;
use router::Router;

extern crate persistent;
use persistent::Read as PRead;
use persistent::State;

extern crate r2d2;
extern crate r2d2_postgres;
use r2d2_postgres::PostgresConnectionManager;
pub type PostgresConnection = r2d2::PooledConnection<PostgresConnectionManager>;

#[macro_use]
extern crate potboiler_common;
use potboiler_common::db;
use potboiler_common::server_id;
use potboiler_common::string_error::StringError;

extern crate serde_json;
extern crate hyper;

use std::env;
use std::io::Read;

mod tables;
extern crate hybrid_clocks;

#[macro_use]
extern crate lazy_static;
use std::ops::Deref;

lazy_static! {
    static ref SERVER_URL: String = env::var("SERVER_URL").expect("Needed SERVER_URL");
}

include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

fn get_req_key<T: Into<String>>(req: &Request, key: T) -> Option<String> {
    req.extensions
        .get::<Router>()
        .unwrap()
        .find(&key.into())
        .map(|s| s.to_string())
}

fn get_key(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "get_key")))
}

fn update_key(req: &mut Request) -> IronResult<Response> {
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let mut json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    let map = json.as_object_mut().unwrap();
    map.insert("table".to_string(),
               serde_json::to_value(&get_req_key(req, "table").unwrap()));
    map.insert("key".to_string(),
               serde_json::to_value(&get_req_key(req, "key").unwrap()));

    let client = hyper::client::Client::new();

    let res = client.post(SERVER_URL.deref())
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("sender ok");
    assert_eq!(res.status, hyper::status::StatusCode::Created);
    Ok(Response::with((status::Ok, "update_key")))
}

fn make_table(conn: &PostgresConnection, table_name: &str) {
    conn.execute(&format!("CREATE TABLE IF NOT EXISTS {} (key VARCHAR(1024) PRIMARY KEY, value JSONB, \
                           crdt JSONB)",
                          &table_name),
                 &[])
        .expect("make table worked");
}

fn string_iron_error(error: &str) -> IronResult<Response> {
    Err(IronError::new(StringError(error.to_string()), (status::BadRequest, error)))
}

fn new_event(req: &mut Request) -> IronResult<Response> {
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    info!("body: {:?}", json);
    let data = json.find("data").unwrap();
    let when: Timestamp<WallT> = serde_json::from_value(json.find("when").unwrap().clone()).unwrap();
    let change: Change = serde_json::from_value(data.clone()).unwrap();
    info!("change: {:?}", change);
    let tables = tables::get_tables(req);
    match tables.get(&change.table) {
        None => return string_iron_error("Can't find table"),
        Some(&val) => {
            match val {
                CRDT::LWW => {
                    match change.op {
                        Operation::Set => {
                            let conn = get_pg_connection!(&req);
                            let stmt =
                                conn.prepare(&format!("select crdt from {} where key=$1", &change.table))
                                    .expect("select prep worked");
                            let results = stmt.query(&[&change.key]).expect("bad query");
                            if results.is_empty() {
                                let lww = LWW {
                                    when: when,
                                    data: change.change.clone(),
                                };
                                conn.execute(&format!("INSERT INTO {} (key, value, crdt) VALUES ($1, $2, \
                                                       $3)",
                                                      &change.table),
                                             &[&change.key, &change.change, &serde_json::to_value(&lww)])
                                    .expect("insert worked");
                                if &change.key == tables::CONFIG_TABLE {
                                    make_table(&conn, &change.key);
                                    tables::add_table(req, &change.key, CRDT::LWW);
                                }
                            } else {
                                let row = results.get(0);
                                let raw_crdt: serde_json::Value = row.get("crdt");
                                let mut lww: LWW = serde_json::from_value(raw_crdt).expect("bad raw crdt");
                                if lww.when < when {
                                    lww.when = when;
                                    conn.execute(&format!("UPDATE {} set value=$2, crdt=$3 where key=$1",
                                                          &change.table),
                                                 &[&change.key, &change.change, &serde_json::to_value(&lww)])
                                        .expect("update worked");
                                } else {
                                    info!("Earlier event, skipping");
                                }
                            }
                        }
                        _ => {
                            return string_iron_error("LWW only supports Set, not Add/Remove");
                        }

                    }
                }
                _ => {
                    return string_iron_error("Only support LWW so far");
                }
            }
        }
    }
    Ok(Response::with(status::NoContent))
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).expect("log config ok");
    let client = hyper::client::Client::new();

    let mut map: serde_json::Map<String, String> = serde_json::Map::new();
    let host: &str = &env::var("HOST").unwrap_or("localhost".to_string());
    map.insert("url".to_string(),
               format!("http://{}:8001/kv/event", host).to_string());
    let res = client.post(&format!("{}/register", SERVER_URL.deref()))
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("Register ok");
    assert_eq!(res.status, hyper::status::StatusCode::NoContent);

    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    make_table(&conn, "_config");
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = Router::new();
    router.get("/kv/:table/:key", get_key);
    router.post("/kv/:table/:key", update_key);
    router.post("/kv/event", new_event);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link_before(PRead::<server_id::ServerId>::one(server_id::setup()));
    chain.link(PRead::<db::PostgresDB>::both(pool));
    let tables = tables::init_tables(&conn);
    chain.link(State::<tables::Tables>::both(tables));
    info!("Potboiler-kv booted");
    Iron::new(chain).http("0.0.0.0:8001").unwrap();
}
<commit_msg>Make KV actually properly store things in _config and make new tables<commit_after>#[macro_use]
extern crate log;
extern crate log4rs;

extern crate iron;
extern crate logger;
extern crate router;
use iron::prelude::*;
use iron::status;
use logger::Logger;
use router::Router;

extern crate persistent;
use persistent::Read as PRead;
use persistent::State;

extern crate r2d2;
extern crate r2d2_postgres;
use r2d2_postgres::PostgresConnectionManager;
pub type PostgresConnection = r2d2::PooledConnection<PostgresConnectionManager>;

#[macro_use]
extern crate potboiler_common;
use potboiler_common::db;
use potboiler_common::server_id;
use potboiler_common::string_error::StringError;

extern crate serde_json;
extern crate hyper;

use std::env;
use std::io::Read;

mod tables;
extern crate hybrid_clocks;

#[macro_use]
extern crate lazy_static;
use std::ops::Deref;

lazy_static! {
    static ref SERVER_URL: String = env::var("SERVER_URL").expect("Needed SERVER_URL");
}

include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

fn get_req_key<T: Into<String>>(req: &Request, key: T) -> Option<String> {
    req.extensions
        .get::<Router>()
        .unwrap()
        .find(&key.into())
        .map(|s| s.to_string())
}

fn get_key(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "get_key")))
}

fn update_key(req: &mut Request) -> IronResult<Response> {
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let mut json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    let map = json.as_object_mut().unwrap();
    map.insert("table".to_string(),
               serde_json::to_value(&get_req_key(req, "table").unwrap()));
    map.insert("key".to_string(),
               serde_json::to_value(&get_req_key(req, "key").unwrap()));

    let client = hyper::client::Client::new();

    let res = client.post(SERVER_URL.deref())
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("sender ok");
    assert_eq!(res.status, hyper::status::StatusCode::Created);
    Ok(Response::with((status::Ok, "update_key")))
}

fn make_table(conn: &PostgresConnection, table_name: &str) {
    conn.execute(&format!("CREATE TABLE IF NOT EXISTS {} (key VARCHAR(1024) PRIMARY KEY, value JSONB, \
                           crdt JSONB)",
                          &table_name),
                 &[])
        .expect("make table worked");
}

fn string_iron_error(error: &str) -> IronResult<Response> {
    Err(IronError::new(StringError(error.to_string()), (status::BadRequest, error)))
}

fn new_event(req: &mut Request) -> IronResult<Response> {
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    info!("body: {:?}", json);
    let data = json.find("data").unwrap();
    let when: Timestamp<WallT> = serde_json::from_value(json.find("when").unwrap().clone()).unwrap();
    let change: Change = serde_json::from_value(data.clone()).unwrap();
    info!("change: {:?}", change);
    let tables = tables::get_tables(req);
    match tables.get(&change.table) {
        None => return string_iron_error("Can't find table"),
        Some(&val) => {
            match val {
                CRDT::LWW => {
                    match change.op {
                        Operation::Set => {
                            let conn = get_pg_connection!(&req);
                            let stmt =
                                conn.prepare(&format!("select crdt from {} where key=$1", &change.table))
                                    .expect("select prep worked");
                            let results = stmt.query(&[&change.key]).expect("bad query");
                            if results.is_empty() {
                                let lww = LWW {
                                    when: when,
                                    data: change.change.clone(),
                                };
                                conn.execute(&format!("INSERT INTO {} (key, value, crdt) VALUES ($1, $2, \
                                                       $3)",
                                                      &change.table),
                                             &[&change.key, &change.change, &serde_json::to_value(&lww)])
                                    .expect("insert worked");
                                if &change.table == tables::CONFIG_TABLE {
                                    make_table(&conn, &change.key);
                                    tables::add_table(req, &change.key, CRDT::LWW);
                                }
                            } else {
                                let row = results.get(0);
                                let raw_crdt: serde_json::Value = row.get("crdt");
                                let mut lww: LWW = serde_json::from_value(raw_crdt).expect("bad raw crdt");
                                if lww.when < when {
                                    lww.when = when;
                                    lww.data = change.change.clone();
                                    conn.execute(&format!("UPDATE {} set value=$2, crdt=$3 where key=$1",
                                                          &change.table),
                                                 &[&change.key, &change.change, &serde_json::to_value(&lww)])
                                        .expect("update worked");
                                } else {
                                    info!("Earlier event, skipping");
                                }
                            }
                        }
                        _ => {
                            return string_iron_error("LWW only supports Set, not Add/Remove");
                        }

                    }
                }
                _ => {
                    return string_iron_error("Only support LWW so far");
                }
            }
        }
    }
    Ok(Response::with(status::NoContent))
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).expect("log config ok");
    let client = hyper::client::Client::new();

    let mut map: serde_json::Map<String, String> = serde_json::Map::new();
    let host: &str = &env::var("HOST").unwrap_or("localhost".to_string());
    map.insert("url".to_string(),
               format!("http://{}:8001/kv/event", host).to_string());
    let res = client.post(&format!("{}/register", SERVER_URL.deref()))
        .body(&serde_json::ser::to_string(&map).unwrap())
        .send()
        .expect("Register ok");
    assert_eq!(res.status, hyper::status::StatusCode::NoContent);

    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    make_table(&conn, "_config");
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = Router::new();
    router.get("/kv/:table/:key", get_key);
    router.post("/kv/:table/:key", update_key);
    router.post("/kv/event", new_event);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    chain.link_before(PRead::<server_id::ServerId>::one(server_id::setup()));
    chain.link(PRead::<db::PostgresDB>::both(pool));
    let tables = tables::init_tables(&conn);
    chain.link(State::<tables::Tables>::both(tables));
    info!("Potboiler-kv booted");
    Iron::new(chain).http("0.0.0.0:8001").unwrap();
}
<|endoftext|>


<commit_before>use super::serde_vistors::HexVisitor;
use super::{PublicKey, SecretKey};
use bls_aggregates::Signature as RawSignature;
use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use ssz::{
    decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash,
};

/// A single BLS signature.
///
/// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ
/// serialization).
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct Signature {
    signature: RawSignature,
    is_empty: bool,
}

impl Signature {
    /// Instantiate a new Signature from a message and a SecretKey.
    pub fn new(msg: &[u8], domain: u64, sk: &SecretKey) -> Self {
        Signature {
            signature: RawSignature::new(msg, domain, sk.as_raw()),
            is_empty: false,
        }
    }

    /// Instantiate a new Signature from a message and a SecretKey, where the message has already
    /// been hashed.
    pub fn new_hashed(x_real_hashed: &[u8], x_imaginary_hashed: &[u8], sk: &SecretKey) -> Self {
        Signature {
            signature: RawSignature::new_hashed(
                x_real_hashed,
                x_imaginary_hashed,
                sk.as_raw(),
            ),
            is_empty: false,
        }
    }

    /// Verify the Signature against a PublicKey.
    pub fn verify(&self, msg: &[u8], domain: u64, pk: &PublicKey) -> bool {
        if self.is_empty {
            return false;
        }
        self.signature.verify(msg, domain, pk.as_raw())
    }

    /// Verify the Signature against a PublicKey, where the message has already been hashed.
    pub fn verify_hashed(
        &self,
        x_real_hashed: &[u8],
        x_imaginary_hashed: &[u8],
        pk: &PublicKey,
    ) -> bool {
        self.signature
            .verify_hashed(x_real_hashed, x_imaginary_hashed, pk.as_raw())
    }

    /// Returns the underlying signature.
    pub fn as_raw(&self) -> &RawSignature {
        &self.signature
    }

    /// Returns a new empty signature.
    pub fn empty_signature() -> Self {
        // Set RawSignature = infinity
        let mut empty: Vec<u8> = vec![0; 96];
        empty[0] += u8::pow(2, 6) + u8::pow(2, 7);
        Signature {
            signature: RawSignature::from_bytes(&empty).unwrap(),
            is_empty: true,
        }
    }

    // Converts a BLS Signature to bytes
    pub fn as_bytes(&self) -> Vec<u8> {
        if self.is_empty {
            return vec![0; 96];
        }
        self.signature.as_bytes()
    }

    // Convert bytes to BLS Signature
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
        for byte in bytes {
            if *byte != 0 {
                let raw_signature = RawSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?;
                return Ok(Signature {
                    signature: raw_signature,
                    is_empty: false,
                });
            }
        }
        Ok(Signature::empty_signature())
    }

    // Check for empty Signature
    pub fn is_empty(&self) -> bool {
        self.is_empty
    }
}

impl Encodable for Signature {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self.as_bytes());
    }
}

impl Decodable for Signature {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (sig_bytes, i) = decode_ssz_list(bytes, i)?;
        let signature = Signature::from_bytes(&sig_bytes)?;
        Ok((signature, i))
    }
}

impl TreeHash for Signature {
    fn hash_tree_root(&self) -> Vec<u8> {
        hash(&self.as_bytes())
    }
}

impl Serialize for Signature {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&hex_encode(ssz_encode(self)))
    }
}

impl<'de> Deserialize<'de> for Signature {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let bytes = deserializer.deserialize_str(HexVisitor)?;
        let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0)
            .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?;
        Ok(pubkey)
    }
}

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

    #[test]
    pub fn test_ssz_round_trip() {
        let keypair = Keypair::random();

        let original = Signature::new(&[42, 42], 0, &keypair.sk);

        let bytes = ssz_encode(&original);
        let (decoded, _) = Signature::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    pub fn test_empty_signature() {
        let sig = Signature::empty_signature();

        let sig_as_bytes: Vec<u8> = sig.as_raw().as_bytes();

        assert_eq!(sig_as_bytes.len(), 96);
        for (i, one_byte) in sig_as_bytes.iter().enumerate() {
            if i == 0 {
                assert_eq!(*one_byte, u8::pow(2, 6) + u8::pow(2, 7));
            } else {
                assert_eq!(*one_byte, 0);
            }
        }
    }
}
<commit_msg>cargo fmt<commit_after>use super::serde_vistors::HexVisitor;
use super::{PublicKey, SecretKey};
use bls_aggregates::Signature as RawSignature;
use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use ssz::{
    decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash,
};

/// A single BLS signature.
///
/// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ
/// serialization).
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct Signature {
    signature: RawSignature,
    is_empty: bool,
}

impl Signature {
    /// Instantiate a new Signature from a message and a SecretKey.
    pub fn new(msg: &[u8], domain: u64, sk: &SecretKey) -> Self {
        Signature {
            signature: RawSignature::new(msg, domain, sk.as_raw()),
            is_empty: false,
        }
    }

    /// Instantiate a new Signature from a message and a SecretKey, where the message has already
    /// been hashed.
    pub fn new_hashed(x_real_hashed: &[u8], x_imaginary_hashed: &[u8], sk: &SecretKey) -> Self {
        Signature {
            signature: RawSignature::new_hashed(x_real_hashed, x_imaginary_hashed, sk.as_raw()),
            is_empty: false,
        }
    }

    /// Verify the Signature against a PublicKey.
    pub fn verify(&self, msg: &[u8], domain: u64, pk: &PublicKey) -> bool {
        if self.is_empty {
            return false;
        }
        self.signature.verify(msg, domain, pk.as_raw())
    }

    /// Verify the Signature against a PublicKey, where the message has already been hashed.
    pub fn verify_hashed(
        &self,
        x_real_hashed: &[u8],
        x_imaginary_hashed: &[u8],
        pk: &PublicKey,
    ) -> bool {
        self.signature
            .verify_hashed(x_real_hashed, x_imaginary_hashed, pk.as_raw())
    }

    /// Returns the underlying signature.
    pub fn as_raw(&self) -> &RawSignature {
        &self.signature
    }

    /// Returns a new empty signature.
    pub fn empty_signature() -> Self {
        // Set RawSignature = infinity
        let mut empty: Vec<u8> = vec![0; 96];
        empty[0] += u8::pow(2, 6) + u8::pow(2, 7);
        Signature {
            signature: RawSignature::from_bytes(&empty).unwrap(),
            is_empty: true,
        }
    }

    // Converts a BLS Signature to bytes
    pub fn as_bytes(&self) -> Vec<u8> {
        if self.is_empty {
            return vec![0; 96];
        }
        self.signature.as_bytes()
    }

    // Convert bytes to BLS Signature
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
        for byte in bytes {
            if *byte != 0 {
                let raw_signature =
                    RawSignature::from_bytes(&bytes).map_err(|_| DecodeError::Invalid)?;
                return Ok(Signature {
                    signature: raw_signature,
                    is_empty: false,
                });
            }
        }
        Ok(Signature::empty_signature())
    }

    // Check for empty Signature
    pub fn is_empty(&self) -> bool {
        self.is_empty
    }
}

impl Encodable for Signature {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self.as_bytes());
    }
}

impl Decodable for Signature {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (sig_bytes, i) = decode_ssz_list(bytes, i)?;
        let signature = Signature::from_bytes(&sig_bytes)?;
        Ok((signature, i))
    }
}

impl TreeHash for Signature {
    fn hash_tree_root(&self) -> Vec<u8> {
        hash(&self.as_bytes())
    }
}

impl Serialize for Signature {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&hex_encode(ssz_encode(self)))
    }
}

impl<'de> Deserialize<'de> for Signature {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let bytes = deserializer.deserialize_str(HexVisitor)?;
        let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0)
            .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?;
        Ok(pubkey)
    }
}

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

    #[test]
    pub fn test_ssz_round_trip() {
        let keypair = Keypair::random();

        let original = Signature::new(&[42, 42], 0, &keypair.sk);

        let bytes = ssz_encode(&original);
        let (decoded, _) = Signature::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    pub fn test_empty_signature() {
        let sig = Signature::empty_signature();

        let sig_as_bytes: Vec<u8> = sig.as_raw().as_bytes();

        assert_eq!(sig_as_bytes.len(), 96);
        for (i, one_byte) in sig_as_bytes.iter().enumerate() {
            if i == 0 {
                assert_eq!(*one_byte, u8::pow(2, 6) + u8::pow(2, 7));
            } else {
                assert_eq!(*one_byte, 0);
            }
        }
    }
}
<|endoftext|>


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

 pub mod inheritance_integrity;
 pub mod privatize;
 pub mod str_to_string;
 pub mod transmute_type;
 pub mod unrooted_must_root;
<commit_msg>auto merge of #4527 : Ms2ger/servo/indentation-plugins, r=larsbergstrom<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pub mod inheritance_integrity;
pub mod privatize;
pub mod str_to_string;
pub mod transmute_type;
pub mod unrooted_must_root;
<|endoftext|>


<commit_before>use collections::BTreeMap;
use core::{cmp, str};
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;

use syscall::data::Stat;
use syscall::error::*;
use syscall::flag::{MODE_DIR, MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::scheme::Scheme;

#[cfg(test)]
mod gen {
    use collections::BTreeMap;
    pub fn gen() -> BTreeMap<&'static [u8], (&'static [u8], bool)> { BTreeMap::new() }
}

#[cfg(not(test))]
#[path="../../build/userspace/initfs.rs"]
mod gen;

struct Handle {
    path: &'static [u8],
    data: &'static [u8],
    mode: u16,
    seek: usize
}

pub struct InitFsScheme {
    next_id: AtomicUsize,
    files: BTreeMap<&'static [u8], (&'static [u8], bool)>,
    handles: RwLock<BTreeMap<usize, Handle>>
}

impl InitFsScheme {
    pub fn new() -> InitFsScheme {
        InitFsScheme {
            next_id: AtomicUsize::new(0),
            files: gen::gen(),
            handles: RwLock::new(BTreeMap::new())
        }
    }
}

impl Scheme for InitFsScheme {
    fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        let path_utf8 = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?;
        let path_trimmed = path_utf8.trim_matches('/');

        //Have to iterate to get the path without allocation
        for entry in self.files.iter() {
            if entry.0 == &path_trimmed.as_bytes() {
                let id = self.next_id.fetch_add(1, Ordering::SeqCst);
                self.handles.write().insert(id, Handle {
                    path: entry.0,
                    data: (entry.1).0,
                    mode: if (entry.1).1 { MODE_DIR |  0o755 } else { MODE_FILE | 0o744 },
                    seek: 0
                });

                return Ok(id)
            }
        }

        Err(Error::new(ENOENT))
    }

    fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
        let (path, data, mode, seek) = {
            let handles = self.handles.read();
            let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
            (handle.path, handle.data, handle.mode, handle.seek)
        };

        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
        self.handles.write().insert(id, Handle {
            path: path,
            data: data,
            mode: mode,
            seek: seek
        });

        Ok(id)
    }

    fn read(&self, id: usize, buffer: &mut [u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;

        let mut i = 0;
        while i < buffer.len() && handle.seek < handle.data.len() {
            buffer[i] = handle.data[handle.seek];
            i += 1;
            handle.seek += 1;
        }

        Ok(i)
    }

    fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
        let mut handles = self.handles.write();
        let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;

        handle.seek = match whence {
            SEEK_SET => cmp::min(handle.data.len(), pos),
            SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize,
            SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize,
            _ => return Err(Error::new(EINVAL))
        };

        Ok(handle.seek)
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handles = self.handles.read();
        let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

        //TODO: Copy scheme part in kernel
        let mut i = 0;
        let scheme_path = b"initfs:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let mut j = 0;
        while i < buf.len() && j < handle.path.len() {
            buf[i] = handle.path[j];
            i += 1;
            j += 1;
        }

        Ok(i)
    }

    fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
        let handles = self.handles.read();
        let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

        stat.st_mode = handle.mode;
        stat.st_uid = 0;
        stat.st_gid = 0;
        stat.st_size = handle.data.len() as u64;

        Ok(0)
    }

    fn fsync(&self, _id: usize) -> Result<usize> {
        Ok(0)
    }

    fn close(&self, id: usize) -> Result<usize> {
        self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
    }
}
<commit_msg>Allow initfs to be written<commit_after>use alloc::arc::Arc;
use collections::{BTreeMap, Vec};
use core::{cmp, str};
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;

use syscall::data::Stat;
use syscall::error::*;
use syscall::flag::{MODE_DIR, MODE_FILE, SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::scheme::Scheme;

#[cfg(test)]
mod gen {
    use collections::BTreeMap;
    pub fn gen() -> BTreeMap<&'static [u8], (&'static [u8], bool)> { BTreeMap::new() }
}

#[cfg(not(test))]
#[path="../../build/userspace/initfs.rs"]
mod gen;

struct Handle {
    path: &'static [u8],
    data: Arc<RwLock<Vec<u8>>>,
    mode: u16,
    seek: usize
}

pub struct InitFsScheme {
    next_id: AtomicUsize,
    files: BTreeMap<&'static [u8], (Arc<RwLock<Vec<u8>>>, bool)>,
    handles: RwLock<BTreeMap<usize, Handle>>
}

impl InitFsScheme {
    pub fn new() -> InitFsScheme {
        let mut files = BTreeMap::new();
        for (path, (data, folder)) in gen::gen() {
            files.insert(path, (Arc::new(RwLock::new(data.to_vec())), folder));
        }

        InitFsScheme {
            next_id: AtomicUsize::new(0),
            files: files,
            handles: RwLock::new(BTreeMap::new())
        }
    }
}

impl Scheme for InitFsScheme {
    fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        let path_utf8 = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?;
        let path_trimmed = path_utf8.trim_matches('/');

        //Have to iterate to get the path without allocation
        for entry in self.files.iter() {
            if entry.0 == &path_trimmed.as_bytes() {
                let id = self.next_id.fetch_add(1, Ordering::SeqCst);
                self.handles.write().insert(id, Handle {
                    path: entry.0,
                    data: (entry.1).0.clone(),
                    mode: if (entry.1).1 { MODE_DIR |  0o755 } else { MODE_FILE | 0o744 },
                    seek: 0
                });

                return Ok(id)
            }
        }

        Err(Error::new(ENOENT))
    }

    fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
        let (path, data, mode, seek) = {
            let handles = self.handles.read();
            let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
            (handle.path, handle.data.clone(), handle.mode, handle.seek)
        };

        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
        self.handles.write().insert(id, Handle {
            path: path,
            data: data,
            mode: mode,
            seek: seek
        });

        Ok(id)
    }

    fn read(&self, id: usize, buffer: &mut [u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
        let data = handle.data.read();

        let mut i = 0;
        while i < buffer.len() && handle.seek < data.len() {
            buffer[i] = data[handle.seek];
            i += 1;
            handle.seek += 1;
        }

        Ok(i)
    }

    fn write(&self, id: usize, buffer: &[u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
        let mut data = handle.data.write();

        let mut i = 0;
        while i < buffer.len() && handle.seek < data.len() {
            data[handle.seek] = buffer[i];
            i += 1;
            handle.seek += 1;
        }

        Ok(i)
    }

    fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
        let mut handles = self.handles.write();
        let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
        let data = handle.data.read();

        handle.seek = match whence {
            SEEK_SET => cmp::min(data.len(), pos),
            SEEK_CUR => cmp::max(0, cmp::min(data.len() as isize, handle.seek as isize + pos as isize)) as usize,
            SEEK_END => cmp::max(0, cmp::min(data.len() as isize, data.len() as isize + pos as isize)) as usize,
            _ => return Err(Error::new(EINVAL))
        };

        Ok(handle.seek)
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handles = self.handles.read();
        let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

        //TODO: Copy scheme part in kernel
        let mut i = 0;
        let scheme_path = b"initfs:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let mut j = 0;
        while i < buf.len() && j < handle.path.len() {
            buf[i] = handle.path[j];
            i += 1;
            j += 1;
        }

        Ok(i)
    }

    fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
        let handles = self.handles.read();
        let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
        let data = handle.data.read();

        stat.st_mode = handle.mode;
        stat.st_uid = 0;
        stat.st_gid = 0;
        stat.st_size = data.len() as u64;

        Ok(0)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let handles = self.handles.read();
        let _handle = handles.get(&id).ok_or(Error::new(EBADF))?;

        Ok(0)
    }

    fn close(&self, id: usize) -> Result<usize> {
        self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u'];
const BAD_STRINGS: [&'static str; 4] = ["ab", "cd", "pq", "xy"];

fn nice(input: &str) -> bool {
    if BAD_STRINGS.iter().any(|&s| input.contains(s)) {
        return false;
    }
    if input.chars().filter(|c| VOWELS.contains(c)).count() < 3 {
        return false;
    }
    if !input.chars().zip(input[1..].chars()).any(|(c1,c2)| c1 == c2) {
        return false;
    }
    true
}

pub fn main() {
    let stdin = io::stdin();
    println!("{}", stdin.lock()
                        .lines()
                        .map(|line| line.unwrap())
                        .filter(|line| nice(&line))
                        .count());
}
<commit_msg>day 5 part 2 rust solution<commit_after>use std::io;
use std::io::prelude::*;
use itertools::Zip;
use std::collections::HashMap;

const VOWELS: [char; 5] = ['a', 'e', 'i', 'o', 'u'];
const BAD_STRINGS: [&'static str; 4] = ["ab", "cd", "pq", "xy"];

fn part1_nice(input: &str) -> bool {
    if BAD_STRINGS.iter().any(|&s| input.contains(s)) {
        return false;
    }
    if input.chars().filter(|c| VOWELS.contains(c)).count() < 3 {
        return false;
    }
    if !input.chars().zip(input[1..].chars()).any(|(c1,c2)| c1 == c2) {
        return false;
    }
    true
}

fn part2_nice(input: &str) -> bool {
    if !Zip::new((input.chars(), input[1..].chars(), input[2..].chars())).any(|(a, _, b)| a == b) {
        return false;
    };
    let mut doubles: HashMap<(char, char), usize> = HashMap::new();
    for (i, (c1, c2)) in Zip::new((input.chars(), input[1..].chars())).enumerate() {
        let j = doubles.entry((c1,c2)).or_insert(i);
        if i > *j + 1 { return true }
    }
    false
}

pub fn main() {
    let stdin = io::stdin();
    let (result1, result2) = stdin.lock()
                               .lines()
                               .map(|line| line.unwrap())
                               .fold((0,0), |(part1, part2), line| {
                                    let part1 = if part1_nice(&line) {
                                        part1 + 1
                                    } else {part1};
                                    let part2 = if part2_nice(&line) {
                                        part2 + 1
                                    } else {part2};
                                    (part1, part2)
                                });
    println!("Part 1: {}\nPart 2: {}", result1, result2);
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufRead, BufReader};
use bstr::io::BufReadExt;

fn main() {
    let filename = "Homo_sapiens.GRCh37.67.dna_rm.chromosome.Y.fa";

    // Open the file in read-only mode (ignoring errors).
    let file = File::open(filename).unwrap();
    let reader = BufReader::new(file);

    let mut at = 0;
    let mut gc = 0;
    // Read the file line by line using the lines() iterator from std::io::BufRead.
    reader.for_byte_line( |line|  {
        if line.first() == Some(&b'>') {
            return Ok(true)
        }
        for c in line {
            match c {
                b'G' => gc += 1,
                b'C' => gc += 1,
                b'A' => at += 1,
                b'T' => at += 1,
                _ => (),
            }
        }
	Ok(true)
    });
    let gc_ratio: f64 = gc as f64 / (gc as f64 + at as f64);
    println!("GC ratio (gc/(gc+at)): {}", gc_ratio);
}
<commit_msg>more rust optimizations<commit_after>use std::fs::File;
use std::io::{BufReader};
use bstr::io::BufReadExt;

fn main() {
    let filename = "Homo_sapiens.GRCh37.67.dna_rm.chromosome.Y.fa";

    let mut cc: [u32; 256] = [0; 256];
    // Open the file in read-only mode (ignoring errors).
    let file = File::open(filename).unwrap();
    let reader = BufReader::new(file);

    // Read the file line by line using the lines() iterator from std::io::BufRead.
    reader.for_byte_line( |line|  {
        if line.first() == Some(&b'>') {
            return Ok(true)
        }
        for c in line { cc[*c as usize] += 1; }
	Ok(true)
    }).unwrap();
    let gc = cc[b'G' as usize] + cc[b'C' as usize];
    let at = cc[b'A' as usize] + cc[b'T' as usize];
    let gc_ratio: f64 = gc as f64 / (gc as f64 + at as f64);
    println!("GC ratio (gc/(gc+at)): {}", gc_ratio);
}
<|endoftext|>