<commit_before>use std::iter::Peekable;
use std::result;

use super::ast::Expression;
use super::scanner::{Scanner, Token, TokenError};

pub type Result<T> = result::Result<T, ParseError>;

#[derive(Debug,PartialEq)]
pub enum ParseError {
    ScanError(TokenError),
    Unexpected(Token),
    UnexpectedEOF,
}

pub struct Parser<'a> {
    scanner: Peekable<Scanner<'a>>,
}

impl<'a> Parser<'a> {
    pub fn new(input: &'a str) -> Self {
        Parser{scanner: Scanner::new(input).peekable()}
    }

    // Assuming we've read an open paren, parse the inner expression and the
    // closing paren.
    fn parse_bracketed_expr(&mut self) -> Result<Expression> {
        let inner = match self.next() {
            Some(Ok(expr)) => expr,
            Some(Err(e)) => return Err(e),
            None => return Err(ParseError::UnexpectedEOF),
        };

        match self.scanner.next() {
            Some(Ok(Token::CloseParen)) => Ok(inner),
            Some(Ok(t)) => Err(ParseError::Unexpected(t)),
            Some(Err(e)) => Err(ParseError::ScanError(e)),
            None => Err(ParseError::UnexpectedEOF),
        }
    }

    // Assuming we've parsed an identifier, parse the rest of the expression.
    fn parse_identifier(&mut self, name: String) -> Result<Expression> {
        match self.scanner.peek() {
            Some(&Ok(Token::OpenParen)) => self.scanner.next(),
            _ => return Ok(Expression::Variable(name)),
        };

        match self.parse_expr_list(&Token::CloseParen) {
            Ok(args) => Ok(Expression::FunctionCall {
                name: name,
                args: args,
            }),
            Err(e) => Err(e),
        }
    }

    // parse_expr_list parses a comma-separated list of expressions until the
    // specified token is found.
    fn parse_expr_list(&mut self, until: &Token) -> Result<Vec<Expression>> {
        let mut expressions = Vec::new();

        let mut done = false;
        if let Some(&Ok(ref t)) = self.scanner.peek() {
            done = t == until;
        }

        if done {
            self.scanner.next();
            return Ok(expressions);
        }

        loop {
            match self.next() {
                Some(Ok(expr)) => expressions.push(expr),
                Some(Err(e)) => return Err(e),
                None => return Err(ParseError::UnexpectedEOF),
            }

            match self.scanner.next() {
                Some(Ok(Token::Comma)) => continue,
                Some(Ok(ref t)) if t == until => return Ok(expressions),
                Some(Ok(t)) => return Err(ParseError::Unexpected(t)),
                Some(Err(e)) => return Err(ParseError::ScanError(e)),
                None => return Err(ParseError::UnexpectedEOF),
            }
        }
    }
}

impl<'a> Iterator for Parser<'a> {
    type Item = Result<Expression>;

    fn next(&mut self) -> Option<Self::Item> {
        let token = match self.scanner.next() {
            None => return None,
            Some(Err(e)) => return Some(Err(ParseError::ScanError(e))),
            Some(Ok(t)) => t,
        };

        let expr_res = match token {
            Token::Nil => Ok(Expression::NilLiteral),
            Token::Boolean(b) => Ok(Expression::BooleanLiteral(b)),
            Token::Number(n) => Ok(Expression::NumberLiteral(n)),
            Token::String(s) => Ok(Expression::StrLiteral(s)),
            Token::OpenParen => self.parse_bracketed_expr(),
            Token::Identifier(s) => self.parse_identifier(s),
            t => Err(ParseError::Unexpected(t)),
        };

        let lhs = match expr_res {
            Ok(e) => e,
            Err(e) => return Some(Err(e)),
        };

        // Check for a binary op.
        let op = match self.scanner.peek() {
            Some(&Ok(ref t)) => {
                if let Some(op) = t.to_binary_op() {
                    op
                } else {
                    return Some(Ok(lhs));
                }
            },
            _ => return Some(Ok(lhs)),
        };
        self.scanner.next();

        let rhs = match self.next() {
            Some(Ok(e)) => e,
            Some(Err(e)) => return Some(Err(e)),
            None => return Some(Err(ParseError::UnexpectedEOF)),
        };

        Some(Ok(Expression::BinaryExpr{
            left: Box::new(lhs),
            op: op,
            right: Box::new(rhs),
        }))
    }
}

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

    #[test]
    fn test_literals() {
        let mut parser = Parser::new(r#"nil true false 1 "foo""#);
        assert_eq!(parser.next(), Some(Ok(Expression::NilLiteral)));
        assert_eq!(parser.next(), Some(Ok(Expression::BooleanLiteral(true))));
        assert_eq!(parser.next(), Some(Ok(Expression::BooleanLiteral(false))));
        assert_eq!(parser.next(), Some(Ok(Expression::NumberLiteral(1.0))));
        assert_eq!(parser.next(), Some(Ok(Expression::StrLiteral("foo".to_owned()))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_parentheses() {
        let mut parser = Parser::new(r#"(nil)(((true)))"#);
        assert_eq!(parser.next(), Some(Ok(Expression::NilLiteral)));
        assert_eq!(parser.next(), Some(Ok(Expression::BooleanLiteral(true))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_identifiers_and_functions() {
        let foo_var = Expression::Variable("foo".to_owned());

        let mut parser = Parser::new(r#"foo foo() foo(foo) foo(foo, foo)"#);
        assert_eq!(parser.next(), Some(Ok(foo_var.clone())));
        assert_eq!(parser.next(), Some(Ok(Expression::FunctionCall{
            name: "foo".to_owned(),
            args: vec![],
        })));
        assert_eq!(parser.next(), Some(Ok(Expression::FunctionCall{
            name: "foo".to_owned(),
            args: vec![foo_var.clone()],
        })));
        assert_eq!(parser.next(), Some(Ok(Expression::FunctionCall{
            name: "foo".to_owned(),
            args: vec![foo_var.clone(), foo_var.clone()],
        })));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_binary_expr() {
        let mut parser = Parser::new(r#"1 + 2 - 3 * 4 / 5"#);

        assert_eq!(parser.next(), Some(Ok(Expression::BinaryExpr{
            left: Box::new(Expression::NumberLiteral(1.0)),
            op: BinaryOp::Add,
            right: Box::new(Expression::BinaryExpr{
                left: Box::new(Expression::NumberLiteral(2.0)),
                op: BinaryOp::Sub,
                right: Box::new(Expression::BinaryExpr{
                    left: Box::new(Expression::NumberLiteral(3.0)),
                    op: BinaryOp::Mul,
                    right: Box::new(Expression::BinaryExpr{
                        left: Box::new(Expression::NumberLiteral(4.0)),
                        op: BinaryOp::Div,
                        right: Box::new(Expression::NumberLiteral(5.0)),
                    }),
                }),
            }),
        })));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_binary_ops() {
        let cases = vec![
            ("+", BinaryOp::Add),
            ("-", BinaryOp::Sub),
            ("*", BinaryOp::Mul),
            ("/", BinaryOp::Div),
            ("==", BinaryOp::Eq),
            ("<", BinaryOp::Lt),
            ("<=", BinaryOp::LtEq),
            (">", BinaryOp::Gt),
            (">=", BinaryOp::GtEq),
        ];

        for (s, op) in cases {
            let expr_str = format!("1 {} 2", s);

            let mut parser = Parser::new(&expr_str);
            assert_eq!(parser.next(), Some(Ok(Expression::BinaryExpr{
                left: Box::new(Expression::NumberLiteral(1.0)),
                op: op,
                right: Box::new(Expression::NumberLiteral(2.0)),
            })));
            assert_eq!(parser.next(), None);
        }
    }
}
<commit_msg>Add assignments to parser<commit_after>use std::iter::Peekable;
use std::result;

use super::ast::Expression;
use super::scanner::{Scanner, Token, TokenError};

pub type Result<T> = result::Result<T, ParseError>;

#[derive(Debug,PartialEq)]
pub enum ParseError {
    ScanError(TokenError),
    Unexpected(Token),
    UnexpectedEOF,
}

pub struct Parser<'a> {
    scanner: Peekable<Scanner<'a>>,
}

impl<'a> Parser<'a> {
    pub fn new(input: &'a str) -> Self {
        Parser{scanner: Scanner::new(input).peekable()}
    }

    // Assuming we've read an open paren, parse the inner expression and the
    // closing paren.
    fn parse_bracketed_expr(&mut self) -> Result<Expression> {
        let inner = match self.next() {
            Some(Ok(expr)) => expr,
            Some(Err(e)) => return Err(e),
            None => return Err(ParseError::UnexpectedEOF),
        };

        match self.scanner.next() {
            Some(Ok(Token::CloseParen)) => Ok(inner),
            Some(Ok(t)) => Err(ParseError::Unexpected(t)),
            Some(Err(e)) => Err(ParseError::ScanError(e)),
            None => Err(ParseError::UnexpectedEOF),
        }
    }

    // Assuming we've parsed an identifier, parse the rest of the expression.
    fn parse_identifier(&mut self, name: String) -> Result<Expression> {
        match self.scanner.peek() {
            Some(&Ok(Token::OpenParen)) => self.scanner.next(),
            _ => return Ok(Expression::Variable(name)),
        };

        match self.parse_expr_list(&Token::CloseParen) {
            Ok(args) => Ok(Expression::FunctionCall {
                name: name,
                args: args,
            }),
            Err(e) => Err(e),
        }
    }

    // parse_expr_list parses a comma-separated list of expressions until the
    // specified token is found.
    fn parse_expr_list(&mut self, until: &Token) -> Result<Vec<Expression>> {
        let mut expressions = Vec::new();

        let mut done = false;
        if let Some(&Ok(ref t)) = self.scanner.peek() {
            done = t == until;
        }

        if done {
            self.scanner.next();
            return Ok(expressions);
        }

        loop {
            match self.next() {
                Some(Ok(expr)) => expressions.push(expr),
                Some(Err(e)) => return Err(e),
                None => return Err(ParseError::UnexpectedEOF),
            }

            match self.scanner.next() {
                Some(Ok(Token::Comma)) => continue,
                Some(Ok(ref t)) if t == until => return Ok(expressions),
                Some(Ok(t)) => return Err(ParseError::Unexpected(t)),
                Some(Err(e)) => return Err(ParseError::ScanError(e)),
                None => return Err(ParseError::UnexpectedEOF),
            }
        }
    }
}

impl<'a> Iterator for Parser<'a> {
    type Item = Result<Expression>;

    fn next(&mut self) -> Option<Self::Item> {
        let token = match self.scanner.next() {
            None => return None,
            Some(Err(e)) => return Some(Err(ParseError::ScanError(e))),
            Some(Ok(t)) => t,
        };

        let expr_res = match token {
            Token::Nil => Ok(Expression::NilLiteral),
            Token::Boolean(b) => Ok(Expression::BooleanLiteral(b)),
            Token::Number(n) => Ok(Expression::NumberLiteral(n)),
            Token::String(s) => Ok(Expression::StrLiteral(s)),
            Token::OpenParen => self.parse_bracketed_expr(),
            Token::Identifier(s) => self.parse_identifier(s),
            t => Err(ParseError::Unexpected(t)),
        };

        let lhs = match expr_res {
            Ok(e) => e,
            Err(e) => return Some(Err(e)),
        };

        // Copy the next token because we might be part of a larger expression.
        let next = match self.scanner.peek().cloned() {
            Some(Ok(t)) => t,
            _ => return Some(Ok(lhs)),
        };

        // Binary expression.
        if let Some(op) = next.to_binary_op() {
            self.scanner.next();
            let rhs = match self.next() {
                Some(Ok(e)) => e,
                Some(Err(e)) => return Some(Err(e)),
                None => return Some(Err(ParseError::UnexpectedEOF)),
            };

            return Some(Ok(Expression::BinaryExpr{
                left: Box::new(lhs),
                op: op,
                right: Box::new(rhs),
            }));
        }

        // Assignment.
        if next == Token::Eq {
            if let Expression::Variable(v) = lhs {
                self.scanner.next();
                let rhs = match self.next() {
                    Some(Ok(e)) => e,
                    Some(Err(e)) => return Some(Err(e)),
                    None => return Some(Err(ParseError::UnexpectedEOF)),
                };

                return Some(Ok(Expression::Assignment{
                    left: v,
                    right: Box::new(rhs),
                }));
            }
        }

        Some(Ok(lhs))
    }
}

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

    #[test]
    fn test_literals() {
        let mut parser = Parser::new(r#"nil true false 1 "foo""#);
        assert_eq!(parser.next(), Some(Ok(Expression::NilLiteral)));
        assert_eq!(parser.next(), Some(Ok(Expression::BooleanLiteral(true))));
        assert_eq!(parser.next(), Some(Ok(Expression::BooleanLiteral(false))));
        assert_eq!(parser.next(), Some(Ok(Expression::NumberLiteral(1.0))));
        assert_eq!(parser.next(), Some(Ok(Expression::StrLiteral("foo".to_owned()))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_parentheses() {
        let mut parser = Parser::new(r#"(nil)(((true)))"#);
        assert_eq!(parser.next(), Some(Ok(Expression::NilLiteral)));
        assert_eq!(parser.next(), Some(Ok(Expression::BooleanLiteral(true))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_identifiers_and_functions() {
        let foo_var = Expression::Variable("foo".to_owned());

        let mut parser = Parser::new(r#"foo foo() foo(foo) foo(foo, foo)"#);
        assert_eq!(parser.next(), Some(Ok(foo_var.clone())));
        assert_eq!(parser.next(), Some(Ok(Expression::FunctionCall{
            name: "foo".to_owned(),
            args: vec![],
        })));
        assert_eq!(parser.next(), Some(Ok(Expression::FunctionCall{
            name: "foo".to_owned(),
            args: vec![foo_var.clone()],
        })));
        assert_eq!(parser.next(), Some(Ok(Expression::FunctionCall{
            name: "foo".to_owned(),
            args: vec![foo_var.clone(), foo_var.clone()],
        })));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_binary_expr() {
        let mut parser = Parser::new(r#"1 + 2 - 3 * 4 / 5"#);

        assert_eq!(parser.next(), Some(Ok(Expression::BinaryExpr{
            left: Box::new(Expression::NumberLiteral(1.0)),
            op: BinaryOp::Add,
            right: Box::new(Expression::BinaryExpr{
                left: Box::new(Expression::NumberLiteral(2.0)),
                op: BinaryOp::Sub,
                right: Box::new(Expression::BinaryExpr{
                    left: Box::new(Expression::NumberLiteral(3.0)),
                    op: BinaryOp::Mul,
                    right: Box::new(Expression::BinaryExpr{
                        left: Box::new(Expression::NumberLiteral(4.0)),
                        op: BinaryOp::Div,
                        right: Box::new(Expression::NumberLiteral(5.0)),
                    }),
                }),
            }),
        })));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn test_binary_ops() {
        let cases = vec![
            ("+", BinaryOp::Add),
            ("-", BinaryOp::Sub),
            ("*", BinaryOp::Mul),
            ("/", BinaryOp::Div),
            ("==", BinaryOp::Eq),
            ("<", BinaryOp::Lt),
            ("<=", BinaryOp::LtEq),
            (">", BinaryOp::Gt),
            (">=", BinaryOp::GtEq),
        ];

        for (s, op) in cases {
            let expr_str = format!("1 {} 2", s);

            let mut parser = Parser::new(&expr_str);
            assert_eq!(parser.next(), Some(Ok(Expression::BinaryExpr{
                left: Box::new(Expression::NumberLiteral(1.0)),
                op: op,
                right: Box::new(Expression::NumberLiteral(2.0)),
            })));
            assert_eq!(parser.next(), None);
        }
    }

    #[test]
    fn test_assignments() {
        let mut parser = Parser::new("x = y = z");

        assert_eq!(parser.next(), Some(Ok(Expression::Assignment{
            left: "x".to_owned(),
            right: Box::new(Expression::Assignment{
                left: "y".to_owned(),
                right: Box::new(Expression::Variable("z".to_owned())),
            }),
        })));
        assert_eq!(parser.next(), None);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for SGX using RDRAND instruction
#[cfg(not(target_feature = "rdrand"))]
use crate::util::LazyBool;
use crate::Error;
use core::arch::x86_64::_rdrand64_step;
use core::mem;
use core::num::NonZeroU32;

// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
const WORD_SIZE: usize = mem::size_of::<u64>();

#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
    for _ in 0..RETRY_LIMIT {
        let mut el = mem::uninitialized();
        if _rdrand64_step(&mut el) == 1 {
            // AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to
            // set CF on bogus random data, so we check these values explictly.
            // See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
            // We perform this check regardless of target to guard against
            // any implementation that incorrectly fails to set CF.
            if el != 0 && el != !0 {
                return Ok(el.to_ne_bytes());
            }
            error!("RDRAND returned {:X}, CPU RNG may be broken", el);
            // Keep looping in case this was a false positive.
        }
    }
    error!("RDRAND failed, CPU issue likely");
    Err(Error::UNKNOWN)
}

// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
#[cfg(all(target_env = "sgx", not(target_feature = "rdrand")))]
compile_error!(
    "SGX targets require 'rdrand' target feature. Enable by using -C target-feature=+rdrnd."
);

#[cfg(target_feature = "rdrand")]
fn is_rdrand_supported() -> bool {
    true
}

// TODO use is_x86_feature_detected!("rdrand") when that works in core. See:
// https://github.com/rust-lang-nursery/stdsimd/issues/464
#[cfg(not(target_feature = "rdrand"))]
fn is_rdrand_supported() -> bool {
    use core::arch::x86_64::__cpuid;
    // SAFETY: All x86_64 CPUs support CPUID leaf 1
    const FLAG: u32 = 1 << 30;
    static HAS_RDRAND: LazyBool = LazyBool::new();
    HAS_RDRAND.unsync_init(|| unsafe { (__cpuid(1).ecx & FLAG) != 0 })
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    if !is_rdrand_supported() {
        return Err(Error::UNAVAILABLE);
    }

    // SAFETY: After this point, rdrand is supported, so calling the rdrand
    // functions is not undefined behavior.
    unsafe { rdrand_exact(dest) }
}

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> {
    // We use chunks_exact_mut instead of chunks_mut as it allows almost all
    // calls to memcpy to be elided by the compiler.
    let mut chunks = dest.chunks_exact_mut(WORD_SIZE);
    for chunk in chunks.by_ref() {
        chunk.copy_from_slice(&rdrand()?);
    }

    let tail = chunks.into_remainder();
    let n = tail.len();
    if n > 0 {
        tail.copy_from_slice(&rdrand()?[..n]);
    }
    Ok(())
}

#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
    None
}
<commit_msg>replace mem::uninitialized with mem::zeroed<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for SGX using RDRAND instruction
#[cfg(not(target_feature = "rdrand"))]
use crate::util::LazyBool;
use crate::Error;
use core::arch::x86_64::_rdrand64_step;
use core::mem;
use core::num::NonZeroU32;

// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
const WORD_SIZE: usize = mem::size_of::<u64>();

#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
    for _ in 0..RETRY_LIMIT {
        let mut el = mem::zeroed();
        if _rdrand64_step(&mut el) == 1 {
            // AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to
            // set CF on bogus random data, so we check these values explictly.
            // See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
            // We perform this check regardless of target to guard against
            // any implementation that incorrectly fails to set CF.
            if el != 0 && el != !0 {
                return Ok(el.to_ne_bytes());
            }
            error!("RDRAND returned {:X}, CPU RNG may be broken", el);
            // Keep looping in case this was a false positive.
        }
    }
    error!("RDRAND failed, CPU issue likely");
    Err(Error::UNKNOWN)
}

// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
#[cfg(all(target_env = "sgx", not(target_feature = "rdrand")))]
compile_error!(
    "SGX targets require 'rdrand' target feature. Enable by using -C target-feature=+rdrnd."
);

#[cfg(target_feature = "rdrand")]
fn is_rdrand_supported() -> bool {
    true
}

// TODO use is_x86_feature_detected!("rdrand") when that works in core. See:
// https://github.com/rust-lang-nursery/stdsimd/issues/464
#[cfg(not(target_feature = "rdrand"))]
fn is_rdrand_supported() -> bool {
    use core::arch::x86_64::__cpuid;
    // SAFETY: All x86_64 CPUs support CPUID leaf 1
    const FLAG: u32 = 1 << 30;
    static HAS_RDRAND: LazyBool = LazyBool::new();
    HAS_RDRAND.unsync_init(|| unsafe { (__cpuid(1).ecx & FLAG) != 0 })
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    if !is_rdrand_supported() {
        return Err(Error::UNAVAILABLE);
    }

    // SAFETY: After this point, rdrand is supported, so calling the rdrand
    // functions is not undefined behavior.
    unsafe { rdrand_exact(dest) }
}

#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [u8]) -> Result<(), Error> {
    // We use chunks_exact_mut instead of chunks_mut as it allows almost all
    // calls to memcpy to be elided by the compiler.
    let mut chunks = dest.chunks_exact_mut(WORD_SIZE);
    for chunk in chunks.by_ref() {
        chunk.copy_from_slice(&rdrand()?);
    }

    let tail = chunks.into_remainder();
    let n = tail.len();
    if n > 0 {
        tail.copy_from_slice(&rdrand()?[..n]);
    }
    Ok(())
}

#[inline(always)]
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> {
    None
}
<|endoftext|>


<commit_before>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std::error::Error;
use std::str::FromStr;
use std::fmt::{Display, Error as FmtError, Formatter};

/// An AWS region.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Region {
    ApNortheast1,
    ApNortheast2,
    ApSoutheast1,
    ApSoutheast2,
    EuCentral1,
    EuWest1,
    SaEast1,
    UsEast1,
    UsWest1,
    UsWest2,
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

impl Display for Region {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let region_str = match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApNortheast2 => "ap-northeast-2",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
        };

        write!(f, "{}", region_str)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        match s {
            "ap-northeast-1" => Ok(Region::ApNortheast1),
            "ap-northeast-2" => Ok(Region::ApNortheast2),
            "ap-southeast-1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" => Ok(Region::ApSoutheast2),
            "eu-central-1" => Ok(Region::EuCentral1),
            "eu-west-1" => Ok(Region::EuWest1),
            "sa-east-1" => Ok(Region::SaEast1),
            "us-east-1" => Ok(Region::UsEast1),
            "us-west-1" => Ok(Region::UsWest1),
            "us-west-2" => Ok(Region::UsWest2),
            s => Err(ParseRegionError::new(s))
        }
    }
}

impl ParseRegionError {
    pub fn new(input: &str) -> Self {
        ParseRegionError {
            message: format!("Not a valid AWS region: {}", input)
        }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

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

    #[test]
    fn from_str() {
        assert_eq!(
            "foo".parse::<Region>().err().expect(
                "Parsing foo as a Region was not an error"
            ).to_string(),
            "Not a valid AWS region: foo".to_owned()
        );
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-northeast-2".parse(), Ok(Region::ApNortheast2));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
    }

    #[test]
    fn region_display() {
        assert_eq!(Region::ApNortheast1.to_string(), "ap-northeast-1".to_owned());
        assert_eq!(Region::ApNortheast2.to_string(), "ap-northeast-2".to_owned());
        assert_eq!(Region::ApSoutheast1.to_string(), "ap-southeast-1".to_owned());
        assert_eq!(Region::ApSoutheast2.to_string(), "ap-southeast-2".to_owned());
        assert_eq!(Region::EuCentral1.to_string(), "eu-central-1".to_owned());
        assert_eq!(Region::EuWest1.to_string(), "eu-west-1".to_owned());
        assert_eq!(Region::SaEast1.to_string(), "sa-east-1".to_owned());
        assert_eq!(Region::UsEast1.to_string(), "us-east-1".to_owned());
        assert_eq!(Region::UsWest1.to_string(), "us-west-1".to_owned());
        assert_eq!(Region::UsWest2.to_string(), "us-west-2".to_owned());
    }
}
<commit_msg>add ap-south-1 region<commit_after>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std::error::Error;
use std::str::FromStr;
use std::fmt::{Display, Error as FmtError, Formatter};

/// An AWS region.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Region {
    ApNortheast1,
    ApNortheast2,
    ApSouth1,
    ApSoutheast1,
    ApSoutheast2,
    EuCentral1,
    EuWest1,
    SaEast1,
    UsEast1,
    UsWest1,
    UsWest2,
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

impl Display for Region {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let region_str = match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApNortheast2 => "ap-northeast-2",
            Region::ApSouth1 => "ap-south-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
        };

        write!(f, "{}", region_str)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        match s {
            "ap-northeast-1" => Ok(Region::ApNortheast1),
            "ap-northeast-2" => Ok(Region::ApNortheast2),
            "ap-south-1" => Ok(Region::ApSouth1),
            "ap-southeast-1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" => Ok(Region::ApSoutheast2),
            "eu-central-1" => Ok(Region::EuCentral1),
            "eu-west-1" => Ok(Region::EuWest1),
            "sa-east-1" => Ok(Region::SaEast1),
            "us-east-1" => Ok(Region::UsEast1),
            "us-west-1" => Ok(Region::UsWest1),
            "us-west-2" => Ok(Region::UsWest2),
            s => Err(ParseRegionError::new(s))
        }
    }
}

impl ParseRegionError {
    pub fn new(input: &str) -> Self {
        ParseRegionError {
            message: format!("Not a valid AWS region: {}", input)
        }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

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

    #[test]
    fn from_str() {
        assert_eq!(
            "foo".parse::<Region>().err().expect(
                "Parsing foo as a Region was not an error"
            ).to_string(),
            "Not a valid AWS region: foo".to_owned()
        );
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-northeast-2".parse(), Ok(Region::ApNortheast2));
        assert_eq!("ap-south-1".parse(), Ok(Region::ApSouth1));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
    }

    #[test]
    fn region_display() {
        assert_eq!(Region::ApNortheast1.to_string(), "ap-northeast-1".to_owned());
        assert_eq!(Region::ApNortheast2.to_string(), "ap-northeast-2".to_owned());
        assert_eq!(Region::ApSouth1.to_string(), "ap-south-1".to_owned());
        assert_eq!(Region::ApSoutheast1.to_string(), "ap-southeast-1".to_owned());
        assert_eq!(Region::ApSoutheast2.to_string(), "ap-southeast-2".to_owned());
        assert_eq!(Region::EuCentral1.to_string(), "eu-central-1".to_owned());
        assert_eq!(Region::EuWest1.to_string(), "eu-west-1".to_owned());
        assert_eq!(Region::SaEast1.to_string(), "sa-east-1".to_owned());
        assert_eq!(Region::UsEast1.to_string(), "us-east-1".to_owned());
        assert_eq!(Region::UsWest1.to_string(), "us-west-1".to_owned());
        assert_eq!(Region::UsWest2.to_string(), "us-west-2".to_owned());
    }
}
<|endoftext|>


<commit_before>extern crate dbus;
use self::dbus::ConnectionItem;

use super::connection::{DBusBusType, DBusConnection};
use super::error::DBusError;
use super::server::DBusServer;

use std::collections::btree_map::{BTreeMap, Entry};

pub struct DBusRunner<'a> {
    conn: DBusConnection,

    servers: BTreeMap<String, DBusServer<'a>>,
}

impl<'a> DBusRunner<'a> {
    pub fn new(bus: DBusBusType) -> Result<DBusRunner<'a>, DBusError> {
        let conn = try!(DBusConnection::get_private(bus));

        Ok(DBusRunner {
            conn: conn,

            servers: BTreeMap::new(),
        })
    }

    pub fn add_server(&'a mut self, name: &str) -> Result<&mut DBusServer<'a>, DBusError> {
        match self.servers.entry(name.to_owned()) {
            Entry::Vacant(v)    => {
                let server = try!(DBusServer::new(&self.conn, name));

                Ok(v.insert(server))
            },
            Entry::Occupied(_)  => Err(DBusError::ServerAlreadyRegistered(name.to_owned())),
        }
    }

    pub fn remove_server(&mut self, name: &str) -> Result<&mut Self, DBusError> {
        match self.servers.remove(name) {
            Some(_) => Ok(self),
            None    => Err(DBusError::NoSuchServer(name.to_owned())),
        }
    }

    pub fn run(&mut self, timeout: i32) -> () {
        let servers = &mut self.servers;

        self.conn.iter(timeout).fold((), |_, item| {
            match item {
                ConnectionItem::MethodCall(m) => Some(m),
                ConnectionItem::Signal(s)     => Some(s),
                ConnectionItem::Nothing       => None,
            }.as_mut().map(|m| {
                servers.iter_mut().fold(Some(m), |opt_m, (_, server)| {
                    opt_m.and_then(|m| {
                        server.handle_message(m)
                    })
                })
            });
        });
    }
}
<commit_msg>runner: try to fix runner lifetime<commit_after>extern crate dbus;
use self::dbus::ConnectionItem;

use super::connection::{DBusBusType, DBusConnection};
use super::error::DBusError;
use super::server::DBusServer;

use std::collections::btree_map::{BTreeMap, Entry};

pub struct DBusRunner<'a> {
    conn: DBusConnection,

    servers: BTreeMap<String, DBusServer<'a>>,
}

impl<'a> DBusRunner<'a> {
    pub fn new(bus: DBusBusType) -> Result<DBusRunner<'a>, DBusError> {
        let conn = try!(DBusConnection::get_private(bus));

        Ok(DBusRunner {
            conn: conn,

            servers: BTreeMap::new(),
        })
    }

    pub fn add_server(&'a mut self, name: &str) -> Result<&'a mut DBusServer<'a>, DBusError> {
        match self.servers.entry(name.to_owned()) {
            Entry::Vacant(v)    => {
                let server = try!(DBusServer::new(&self.conn, name));

                Ok(v.insert(server))
            },
            Entry::Occupied(_)  => Err(DBusError::ServerAlreadyRegistered(name.to_owned())),
        }
    }

    pub fn remove_server(&mut self, name: &str) -> Result<&mut Self, DBusError> {
        match self.servers.remove(name) {
            Some(_) => Ok(self),
            None    => Err(DBusError::NoSuchServer(name.to_owned())),
        }
    }

    pub fn run(&mut self, timeout: i32) -> () {
        let servers = &mut self.servers;

        self.conn.iter(timeout).fold((), |_, item| {
            match item {
                ConnectionItem::MethodCall(m) => Some(m),
                ConnectionItem::Signal(s)     => Some(s),
                ConnectionItem::Nothing       => None,
            }.as_mut().map(|m| {
                servers.iter_mut().fold(Some(m), |opt_m, (_, server)| {
                    opt_m.and_then(|m| {
                        server.handle_message(m)
                    })
                })
            });
        });
    }
}
<|endoftext|>


<commit_before>// run-pass
#![allow(non_camel_case_types)]

// ignore-emscripten FIXME(#45351) hits an LLVM assert

#![feature(repr_simd, platform_intrinsics)]

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x4(pub u32, pub u32, pub u32, pub u32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct i32x4(pub i32, pub i32, pub i32, pub i32);

extern "platform-intrinsic" {
    fn simd_saturating_add<T>(x: T, y: T) -> T;
    fn simd_saturating_sub<T>(x: T, y: T) -> T;
}

fn main() {
    // unsigned
    {
        const M: u32 = u32::max_value();

        let a = u32x4(1, 2, 3, 4);
        let b = u32x4(2, 4, 6, 8);
        let m = u32x4(M, M, M, M);
        let m1 = u32x4(M - 1, M - 1, M - 1, M - 1);
        let z = u32x4(0, 0, 0, 0);

        unsafe {
            assert_eq!(simd_saturating_add(z, z), z);
            assert_eq!(simd_saturating_add(z, a), a);
            assert_eq!(simd_saturating_add(b, z), b);
            assert_eq!(simd_saturating_add(a, a), b);
            assert_eq!(simd_saturating_add(a, m), m);
            assert_eq!(simd_saturating_add(m, b), m);
            assert_eq!(simd_saturating_add(m1, a), m);

            assert_eq!(simd_saturating_sub(b, z), b);
            assert_eq!(simd_saturating_sub(b, a), a);
            assert_eq!(simd_saturating_sub(a, a), z);
            assert_eq!(simd_saturating_sub(a, b), z);
            assert_eq!(simd_saturating_sub(a, m1), z);
            assert_eq!(simd_saturating_sub(b, m1), z);
        }
    }

    // signed
    {
        const MIN: i32 = i32::min_value();
        const MAX: i32 = i32::max_value();

        let a = i32x4(1, 2, 3, 4);
        let b = i32x4(2, 4, 6, 8);
        let c = i32x4(-1, -2, -3, -4);
        let d = i32x4(-2, -4, -6, -8);

        let max = i32x4(MAX, MAX, MAX, MAX);
        let max1 = i32x4(MAX - 1, MAX - 1, MAX - 1, MAX - 1);
        let min = i32x4(MIN, MIN, MIN, MIN);
        let min1 = i32x4(MIN + 1, MIN + 1, MIN + 1, MIN + 1);

        let z = i32x4(0, 0, 0, 0);

        unsafe {
            assert_eq!(simd_saturating_add(z, z), z);
            assert_eq!(simd_saturating_add(z, a), a);
            assert_eq!(simd_saturating_add(b, z), b);
            assert_eq!(simd_saturating_add(a, a), b);
            assert_eq!(simd_saturating_add(a, max), max);
            assert_eq!(simd_saturating_add(max, b), max);
            assert_eq!(simd_saturating_add(max1, a), max);
            assert_eq!(simd_saturating_add(min1, z), min1);
            assert_eq!(simd_saturating_add(min, z), min);
            assert_eq!(simd_saturating_add(min1, c), min);
            assert_eq!(simd_saturating_add(min, c), min);
            assert_eq!(simd_saturating_add(min1, d), min);
            assert_eq!(simd_saturating_add(min, d), min);

            assert_eq!(simd_saturating_sub(b, z), b);
            assert_eq!(simd_saturating_sub(b, a), a);
            assert_eq!(simd_saturating_sub(a, a), z);
            assert_eq!(simd_saturating_sub(a, b), c);
            assert_eq!(simd_saturating_sub(z, max), min1);
            assert_eq!(simd_saturating_sub(min1, z), min1);
            assert_eq!(simd_saturating_sub(min1, a), min);
            assert_eq!(simd_saturating_sub(min1, b), min);
        }
    }
}
<commit_msg>simd-saturating-arith test requires LLVM >= 8.0<commit_after>// run-pass
// ignore-emscripten
// min-llvm-version 8.0

#![allow(non_camel_case_types)]
#![feature(repr_simd, platform_intrinsics)]

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct u32x4(pub u32, pub u32, pub u32, pub u32);

#[repr(simd)]
#[derive(Copy, Clone, PartialEq, Debug)]
struct i32x4(pub i32, pub i32, pub i32, pub i32);

extern "platform-intrinsic" {
    fn simd_saturating_add<T>(x: T, y: T) -> T;
    fn simd_saturating_sub<T>(x: T, y: T) -> T;
}

fn main() {
    // unsigned
    {
        const M: u32 = u32::max_value();

        let a = u32x4(1, 2, 3, 4);
        let b = u32x4(2, 4, 6, 8);
        let m = u32x4(M, M, M, M);
        let m1 = u32x4(M - 1, M - 1, M - 1, M - 1);
        let z = u32x4(0, 0, 0, 0);

        unsafe {
            assert_eq!(simd_saturating_add(z, z), z);
            assert_eq!(simd_saturating_add(z, a), a);
            assert_eq!(simd_saturating_add(b, z), b);
            assert_eq!(simd_saturating_add(a, a), b);
            assert_eq!(simd_saturating_add(a, m), m);
            assert_eq!(simd_saturating_add(m, b), m);
            assert_eq!(simd_saturating_add(m1, a), m);

            assert_eq!(simd_saturating_sub(b, z), b);
            assert_eq!(simd_saturating_sub(b, a), a);
            assert_eq!(simd_saturating_sub(a, a), z);
            assert_eq!(simd_saturating_sub(a, b), z);
            assert_eq!(simd_saturating_sub(a, m1), z);
            assert_eq!(simd_saturating_sub(b, m1), z);
        }
    }

    // signed
    {
        const MIN: i32 = i32::min_value();
        const MAX: i32 = i32::max_value();

        let a = i32x4(1, 2, 3, 4);
        let b = i32x4(2, 4, 6, 8);
        let c = i32x4(-1, -2, -3, -4);
        let d = i32x4(-2, -4, -6, -8);

        let max = i32x4(MAX, MAX, MAX, MAX);
        let max1 = i32x4(MAX - 1, MAX - 1, MAX - 1, MAX - 1);
        let min = i32x4(MIN, MIN, MIN, MIN);
        let min1 = i32x4(MIN + 1, MIN + 1, MIN + 1, MIN + 1);

        let z = i32x4(0, 0, 0, 0);

        unsafe {
            assert_eq!(simd_saturating_add(z, z), z);
            assert_eq!(simd_saturating_add(z, a), a);
            assert_eq!(simd_saturating_add(b, z), b);
            assert_eq!(simd_saturating_add(a, a), b);
            assert_eq!(simd_saturating_add(a, max), max);
            assert_eq!(simd_saturating_add(max, b), max);
            assert_eq!(simd_saturating_add(max1, a), max);
            assert_eq!(simd_saturating_add(min1, z), min1);
            assert_eq!(simd_saturating_add(min, z), min);
            assert_eq!(simd_saturating_add(min1, c), min);
            assert_eq!(simd_saturating_add(min, c), min);
            assert_eq!(simd_saturating_add(min1, d), min);
            assert_eq!(simd_saturating_add(min, d), min);

            assert_eq!(simd_saturating_sub(b, z), b);
            assert_eq!(simd_saturating_sub(b, a), a);
            assert_eq!(simd_saturating_sub(a, a), z);
            assert_eq!(simd_saturating_sub(a, b), c);
            assert_eq!(simd_saturating_sub(z, max), min1);
            assert_eq!(simd_saturating_sub(min1, z), min1);
            assert_eq!(simd_saturating_sub(min1, a), min);
            assert_eq!(simd_saturating_sub(min1, b), min);
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "nightly")]
#![feature(test)]

extern crate test;
extern crate delta_l as dl;

use std::io::{Write, Seek, SeekFrom, Result};

const TEST_DATA: &'static[u8] = include_bytes!("../test_data/bench.txt");
const TEST_DATA_DELTA: &'static[u8] = include_bytes!("../test_data/bench.txt.delta");

#[derive(Default, Debug, Clone)]
struct SeekableSink(());

impl Write for SeekableSink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> Result<usize> { Ok(buf.len()) }
    #[inline]
    fn flush(&mut self) -> Result<()> { Ok(()) }
}

impl Seek for SeekableSink {
    fn seek(&mut self, _: SeekFrom) -> Result<u64> {
        Ok(0)
    }
}

#[bench]
fn encrypt(b: &mut test::Bencher){
    b.iter(|| test::black_box(dl::encode_with_checksum([0; 8], &mut TEST_DATA, &mut SeekableSink::default())).unwrap());
}

#[bench]
fn decrypt(b: &mut test::Bencher){
    b.iter(|| test::black_box(dl::decode([0; 8], &mut TEST_DATA_DELTA, &mut SeekableSink::default())).unwrap());
}
<commit_msg>Add checksum-less benches<commit_after>#![cfg(feature = "nightly")]
#![feature(test)]

extern crate test;
extern crate delta_l as dl;

use std::io::{Write, Seek, SeekFrom, Result};

const TEST_DATA: &'static[u8] = include_bytes!("../test_data/bench.txt");
const TEST_DATA_DELTA: &'static[u8] = include_bytes!("../test_data/bench.txt.delta");
const TEST_DATA_DELTA_NOC: &'static[u8] = include_bytes!("../test_data/bench.txt.delta-noc");

#[derive(Default, Debug, Clone)]
struct SeekableSink(());

impl Write for SeekableSink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> Result<usize> { Ok(buf.len()) }
    #[inline]
    fn flush(&mut self) -> Result<()> { Ok(()) }
}

impl Seek for SeekableSink {
    fn seek(&mut self, _: SeekFrom) -> Result<u64> {
        Ok(0)
    }
}

#[bench]
fn encrypt(b: &mut test::Bencher){
    b.iter(|| test::black_box(dl::encode_with_checksum([0; 8], &mut TEST_DATA, &mut SeekableSink::default())).unwrap());
}

#[bench]
fn encrypt_no_checksum(b: &mut test::Bencher){
    b.iter(|| test::black_box(dl::encode_no_checksum([0; 8], &mut TEST_DATA, &mut SeekableSink::default())).unwrap());
}

#[bench]
fn decrypt(b: &mut test::Bencher){
    b.iter(|| test::black_box(dl::decode([0; 8], &mut TEST_DATA_DELTA, &mut SeekableSink::default())).unwrap());
}

#[bench]
fn decrypt_no_checksum(b: &mut test::Bencher){
    b.iter(|| test::black_box(dl::decode([0; 8], &mut TEST_DATA_DELTA_NOC, &mut SeekableSink::default())).unwrap());
}
<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = match WebSessionImpl::new() {
            Ok(session) => {
                FromServer::new(None::<LocalClient>, box session)
            }
            Err(_e) => {
                return context.fail();
            }
        };
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> sqlite3::SqliteResult<WebSessionImpl> {
        let db = try!(sqlite3::open("/var/data.db"));
        db.set_busy_timeout(1000); // try for a least a second
        Ok(WebSessionImpl {
            db : db,
        })
    }
}

impl UiSession::Server for WebSessionImpl {

}

impl WebSessionImpl {

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.is_alphanumeric() { return Ok(false); }

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {

        if definition.len() != word.len() { return Ok(false); }

        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d[0] == word[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {

        let time : i64 = ::time::get_time().sec;
        let mut query = StrBuf::new();
        query.push_str(format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str(";");
        query.push_str(format!("DELETE FROM Log WHERE Word=\"{}\";", word));
        query.push_str(format!("INSERT INTO Log(Word, Timestamp) VALUES(\"{}\",{});", word, time));
        query.push_str("COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(query.as_slice()));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<~str> {

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<int, ~str>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row.get(&"Definer".to_owned()) { &sqlite3::Text(ref t) => t.clone(), _ => fail!(), };
                    let idx = match row.get(&"Idx".to_owned()) { &sqlite3::Integer(ref i) => i.clone(), _ => fail!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok("
this word has no definition yet
".to_owned());
        } else {

            let mut result = StrBuf::new();
            result.push_str("
");
            for idx in range::<int>(0, word.len() as int) {
                let definer : &str = map.get(&idx).as_slice();
                result.push_str(format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result.into_owned());
        }
    }

    fn count_defs(&self) -> sqlite3::SqliteResult<(int, int, Vec<~str>)> {
        let cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Words;", &None));
        assert!(cursor.step() == sqlite3::SQLITE_ROW);
        let num_words = cursor.get_int(0);

        let cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Definitions WHERE Idx = 0;", &None));
        assert!(cursor.step() == sqlite3::SQLITE_ROW);
        let defined_words = cursor.get_int(0);

        let mut recent_words = Vec::new();
        let cursor = try!(
            self.db.prepare("SELECT Word, Timestamp FROM Log ORDER BY Timestamp DESC LIMIT 5;", &None));
        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let word : ~str = match row.get(&"Word".to_owned()) {&sqlite3::Text(ref t) => t.clone(), _ => fail!(),};
                    recent_words.push(word);
                }
            }
        }
        Ok((defined_words, num_words, recent_words))

    }

    fn construct_page_data(&self, path : &::url::Path) -> sqlite3::SqliteResult<PageData> {
        if path.path.as_slice() == "define" {

            let mut query_map = HashMap::<~str, ~str>::new();
            for &(ref k, ref v) in path.query.iter() {
                query_map.insert(k.clone(), v.clone());
            }

            let word : ~str = match query_map.find(&"word".to_owned()) {
                Some(w) if try!(self.is_word(*w)) => {
                    w.clone()
                }
                _ => {
                    return Ok(Error("that's not a word".to_owned()))
                }
            };

            match query_map.find(&"definition".to_owned()) {
                None => {
                    let def_div = try!(self.get_def(word));

                    return Ok(WordAndDef(word, def_div, None));
                }
                Some(def_query) => {

                    let definition : ~[&str] = def_query.split('+').collect();

                    if try!(self.validate_def(word, definition)) {

                        try!(self.write_def(word, definition));
                        let def_div = try!(self.get_def(word));
                        return Ok(WordAndDef(word,
                                             def_div,
                                             None));
                    } else {
                        let def_div = try!(self.get_def(word));
                        return Ok(WordAndDef(word, def_div, Some("invalid definition".to_owned())))
                    }
                }
            }

        } else {
            let (num_defined, total, recent) = try!(self.count_defs());
            return Ok(HomePage(num_defined, total, recent));
        }
    }

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
     div {
          padding-bottom: 10pt;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

static lookup_form : &'static str =
      r#"<form action="define" method="get">
          <input name="word" maxlength="100"/><button>find word</button></form>"#;

fn define_form(word :&str) -> ~str {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\" maxlength=\"2000\"/>
                   <button>submit definition</button></form>", word=word)
}

enum PageData {
    Error(~str),
    WordAndDef(~str, ~str, Option<~str>),
    HomePage(int, int, Vec<~str>),
}

fn construct_html(page_data : PageData) -> ~str {
    let mut result = StrBuf::new();
    result.push_str(format!("{}", header));

    static home_link : &'static str = "home";
    match page_data {
        Error(e) => {
            result.push_str(format!("
 {}
", e));
            result.push_str(lookup_form);
            result.push_str(home_link);
        }
        WordAndDef(word, def_div, err) => {
            result.push_str(format!("
{}
", word));

            result.push_str(def_div);

            match err {
                None => {}
                Some(e) => {
                    result.push_str(format!("
{}
", e));
                }
            }

            result.push_str(define_form(word));
            result.push_str(home_link);
        }
        HomePage(num_defined, total, recent) => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable, acronym-only dictionary.
");
            result.push_str(format!("
So far, we have defined {} out of {} words.
",
                                    num_defined, total));
            if recent.len() > 0 {
                result.push_str("
Recently modified words: ");
                let mut idx = 0;
                for w in recent.iter() {
                    if idx != 0 {
                        result.push_str(", ");
                    }
                    result.push_str(format!("{word}", word=*w));
                    idx += 1;
                }
                result.push_str(".
");
            }
            result.push_str(lookup_form);
        }
    }

    result.push_str("");
    result.into_owned()
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = match ::url::path_from_str(raw_path) {
            Err(_e) => ::url::Path::new("".to_owned(), Vec::new(), None),
            Ok(p) => p,
        };

        println!("path = {}", raw_path);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else {
            let page_data = match self.construct_page_data(&path) {
                Err(e) => { Error(format!("database error: {} ({})", e, self.db.get_errmsg())) }
                Ok(page_data) => { page_data }
            };
            content.get_body().set_bytes(construct_html(page_data).as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : Box<::std::rt::rtio::RtioFileStream:Send>,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<Box<ClientHook:Send>> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, box UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let args = ::std::os::args();

    if args.len() == 4 && args[1].as_slice() == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(args[2].as_slice());
        let proddb_path = ::std::path::Path::new(args[3].as_slice());
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
        println!("success!");
    }

    // sandstorm launches us with a connection file descriptor 3
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>more detildification<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = match WebSessionImpl::new() {
            Ok(session) => {
                FromServer::new(None::<LocalClient>, box session)
            }
            Err(_e) => {
                return context.fail();
            }
        };
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> sqlite3::SqliteResult<WebSessionImpl> {
        let db = try!(sqlite3::open("/var/data.db"));
        db.set_busy_timeout(1000); // try for a least a second
        Ok(WebSessionImpl {
            db : db,
        })
    }
}

impl UiSession::Server for WebSessionImpl {

}

impl WebSessionImpl {

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.is_alphanumeric() { return Ok(false); }

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));

        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {

        if definition.len() != word.len() { return Ok(false); }

        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d[0] == word[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {

        let time : i64 = ::time::get_time().sec;
        let mut query = StrBuf::new();
        query.push_str(format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str(";");
        query.push_str(format!("DELETE FROM Log WHERE Word=\"{}\";", word));
        query.push_str(format!("INSERT INTO Log(Word, Timestamp) VALUES(\"{}\",{});", word, time));
        query.push_str("COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(query.as_slice()));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<~str> {

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<int, ~str>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row.get(&"Definer".to_owned()) { &sqlite3::Text(ref t) => t.clone(), _ => fail!(), };
                    let idx = match row.get(&"Idx".to_owned()) { &sqlite3::Integer(ref i) => i.clone(), _ => fail!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok("
this word has no definition yet
".to_owned());
        } else {

            let mut result = StrBuf::new();
            result.push_str("
");
            for idx in range::<int>(0, word.len() as int) {
                let definer : &str = map.get(&idx).as_slice();
                result.push_str(format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result.into_owned());
        }
    }

    fn count_defs(&self) -> sqlite3::SqliteResult<(int, int, Vec<~str>)> {
        let cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Words;", &None));
        assert!(cursor.step() == sqlite3::SQLITE_ROW);
        let num_words = cursor.get_int(0);

        let cursor = try!(self.db.prepare("SELECT COUNT(*) FROM Definitions WHERE Idx = 0;", &None));
        assert!(cursor.step() == sqlite3::SQLITE_ROW);
        let defined_words = cursor.get_int(0);

        let mut recent_words = Vec::new();
        let cursor = try!(
            self.db.prepare("SELECT Word, Timestamp FROM Log ORDER BY Timestamp DESC LIMIT 5;", &None));
        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let word : ~str = match row.get(&"Word".to_owned()) {&sqlite3::Text(ref t) => t.clone(), _ => fail!(),};
                    recent_words.push(word);
                }
            }
        }
        Ok((defined_words, num_words, recent_words))

    }

    fn construct_page_data(&self, path : &::url::Path) -> sqlite3::SqliteResult<PageData> {
        if path.path.as_slice() == "define" {

            let mut query_map = HashMap::<~str, ~str>::new();
            for &(ref k, ref v) in path.query.iter() {
                query_map.insert(k.clone(), v.clone());
            }

            let word : ~str = match query_map.find(&"word".to_owned()) {
                Some(w) if try!(self.is_word(*w)) => {
                    w.clone()
                }
                _ => {
                    return Ok(Error("that's not a word".to_owned()))
                }
            };

            match query_map.find(&"definition".to_owned()) {
                None => {
                    let def_div = try!(self.get_def(word));

                    return Ok(WordAndDef(word, def_div, None));
                }
                Some(def_query) => {

                    let definition : Vec<&str> = def_query.split('+').collect();

                    if try!(self.validate_def(word, definition.as_slice())) {

                        try!(self.write_def(word, definition.as_slice()));
                        let def_div = try!(self.get_def(word));
                        return Ok(WordAndDef(word,
                                             def_div,
                                             None));
                    } else {
                        let def_div = try!(self.get_def(word));
                        return Ok(WordAndDef(word, def_div, Some("invalid definition".to_owned())))
                    }
                }
            }

        } else {
            let (num_defined, total, recent) = try!(self.count_defs());
            return Ok(HomePage(num_defined, total, recent));
        }
    }

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
     div {
          padding-bottom: 10pt;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     .title {
       text-align: center;
       font-size:500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

static lookup_form : &'static str =
      r#"<form action="define" method="get">
          <input name="word" maxlength="100"/><button>find word</button></form>"#;

fn define_form(word :&str) -> ~str {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\" maxlength=\"2000\"/>
                   <button>submit definition</button></form>", word=word)
}

enum PageData {
    Error(~str),
    WordAndDef(~str, ~str, Option<~str>),
    HomePage(int, int, Vec<~str>),
}

fn construct_html(page_data : PageData) -> ~str {
    let mut result = StrBuf::new();
    result.push_str(format!("{}", header));

    static home_link : &'static str = "home";
    match page_data {
        Error(e) => {
            result.push_str(format!("
 {}
", e));
            result.push_str(lookup_form);
            result.push_str(home_link);
        }
        WordAndDef(word, def_div, err) => {
            result.push_str(format!("
{}
", word));

            result.push_str(def_div);

            match err {
                None => {}
                Some(e) => {
                    result.push_str(format!("
{}
", e));
                }
            }

            result.push_str(define_form(word));
            result.push_str(home_link);
        }
        HomePage(num_defined, total, recent) => {
            result.push_str("
Acronymy
");
            result.push_str("
A user-editable, acronym-only dictionary.
");
            result.push_str(format!("
So far, we have defined {} out of {} words.
",
                                    num_defined, total));
            if recent.len() > 0 {
                result.push_str("
Recently modified words: ");
                let mut idx = 0;
                for w in recent.iter() {
                    if idx != 0 {
                        result.push_str(", ");
                    }
                    result.push_str(format!("{word}", word=*w));
                    idx += 1;
                }
                result.push_str(".
");
            }
            result.push_str(lookup_form);
        }
    }

    result.push_str("");
    result.into_owned()
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = match ::url::path_from_str(raw_path) {
            Err(_e) => ::url::Path::new("".to_owned(), Vec::new(), None),
            Ok(p) => p,
        };

        println!("path = {}", raw_path);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else {
            let page_data = match self.construct_page_data(&path) {
                Err(e) => { Error(format!("database error: {} ({})", e, self.db.get_errmsg())) }
                Ok(page_data) => { page_data }
            };
            content.get_body().set_bytes(construct_html(page_data).as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : Box<::std::rt::rtio::RtioFileStream:Send>,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<Box<ClientHook:Send>> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, box UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let args = ::std::os::args();

    if args.len() == 4 && args.get(1).as_slice() == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(args.get(2).as_slice());
        let proddb_path = ::std::path::Path::new(args.get(3).as_slice());
        println!("copying database from {} to {}", args.get(2), args.get(3));
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
        println!("success!");
    }

    // sandstorm launches us with a connection file descriptor 3
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {
    fn is_word(&mut self, word : &str) -> sqlite3::SqliteResult<bool> {
        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));
        println!("got the cursor");
        return Ok(try!(cursor.step_row()).is_some());
    }
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = path.query.get(&~"word").clone();

            // TODO check that `word` is actually a word.
            match self.is_word(word) {
                Err(e) => fail!("is_word error: {}, {:?}", e, self.db.get_errmsg()),
                Ok(false) => {
                    content.get_body().set_bytes(
                        html_body(
                            "
 that's not a word

                           <form action=\"define\" method=\"get\">
                           <input name=\"word\"/><button>go</button></form>").as_bytes());
                    return context.done();
                }
                Ok(true) => {}
            }

            content.get_body().set_bytes(
                html_body(
                    format!(
                        "
{word}

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
                     <input name=\"definition\"/><button>define</button></form>",
                        word=word)).as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>copy the database over to var if it's not already there<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {
    fn is_word(&mut self, word : &str) -> sqlite3::SqliteResult<bool> {
        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));
        println!("got the cursor");
        return Ok(try!(cursor.step_row()).is_some());
    }
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = path.query.get(&~"word").clone();

            // TODO check that `word` is actually a word.
            match self.is_word(word) {
                Err(e) => fail!("is_word error: {}, {:?}", e, self.db.get_errmsg()),
                Ok(false) => {
                    content.get_body().set_bytes(
                        html_body(
                            "
 that's not a word

                           <form action=\"define\" method=\"get\">
                           <input name=\"word\"/><button>go</button></form>").as_bytes());
                    return context.done();
                }
                Ok(true) => {}
            }

            content.get_body().set_bytes(
                html_body(
                    format!(
                        "
{word}

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
                     <input name=\"definition\"/><button>define</button></form>",
                        word=word)).as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let initdb_path = ::std::path::Path::new("/data.db");
    let proddb_path = ::std::path::Path::new("/var/data.db");

    if !proddb_path.exists() {
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
    }

    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>


<commit_before>use crate::generate::heightmap::HeightmapCache;
use crate::mapfile::MapFile;
use crate::terrain::quadtree::node::VNode;
use crate::terrain::tile_cache::LayerType;
use anyhow::Error;
use std::sync::Arc;
use std::thread;
use tokio::runtime::Runtime;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};

#[derive(Debug)]
struct TileRequest {
    node: VNode,
    layer: LayerType,
}

#[derive(Debug)]
pub(crate) struct TileResult {
    pub node: VNode,
    pub layer: LayerType,
    pub data: Vec<u8>,
}

pub(crate) struct TileStreamerEndpoint {
    sender: UnboundedSender<TileRequest>,
    receiver: crossbeam::channel::Receiver<TileResult>,
    num_inflight: usize,
}
impl TileStreamerEndpoint {
    pub(crate) fn new(mapfile: Arc<MapFile>) -> Result<Self, Error> {
        let (sender, requests) = unbounded_channel();
        let (results, receiver) = crossbeam::channel::unbounded();

        let rt = Runtime::new()?;
        thread::spawn(move || {
            rt.block_on(async {
                TileStreamer {
                    requests,
                    results,
                    heightmap_tiles: HeightmapCache::new(
                        mapfile.layers()[LayerType::Heightmaps].clone(),
                        32,
                    ),
                    mapfile,
                }
                .run()
                .await
            })
        });

        Ok(Self { sender, receiver, num_inflight: 0 })
    }

    pub(crate) fn request_tile(&mut self, node: VNode, layer: LayerType) {
        self.sender.send(TileRequest { node, layer }).unwrap();
        self.num_inflight += 1;
    }

    pub(crate) fn try_complete(&mut self) -> Option<TileResult> {
        if let Ok(result) = self.receiver.try_recv() {
            self.num_inflight -= 1;
            Some(result)
        } else {
            None
        }
    }

    pub(crate) fn num_inflight(&self) -> usize {
        self.num_inflight
    }
}

struct TileStreamer {
    requests: UnboundedReceiver<TileRequest>,
    results: crossbeam::channel::Sender<TileResult>,
    mapfile: Arc<MapFile>,
    heightmap_tiles: HeightmapCache,
}

impl TileStreamer {
    async fn run(mut self) -> Result<(), Error> {
        while let Some(request) = self.requests.recv().await {
            let data = match request.layer {
                LayerType::Heightmaps => {
                    let heights: Vec<_> = self
                        .heightmap_tiles
                        .get_tile(&*self.mapfile, request.node)
                        .await
                        .unwrap()
                        .iter()
                        .map(|&i| i as f32)
                        .collect();
                    let mut data = vec![0; heights.len() * 4];
                    data.copy_from_slice(bytemuck::cast_slice(&heights));
                    data
                }
                _ => self.mapfile.read_tile(request.layer, request.node).unwrap(),
            };
            self.results.send(TileResult { node: request.node, layer: request.layer, data })?;
        }
        Ok(())
    }
}
<commit_msg>More concurrency with tile streaming<commit_after>use crate::generate::heightmap::HeightmapCache;
use crate::mapfile::MapFile;
use crate::terrain::quadtree::node::VNode;
use crate::terrain::tile_cache::LayerType;
use anyhow::Error;
use std::sync::Arc;
use std::thread;
use tokio::runtime::Runtime;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use futures::{FutureExt, StreamExt};

#[derive(Copy, Clone, Debug)]
struct TileRequest {
    node: VNode,
    layer: LayerType,
}

#[derive(Debug)]
pub(crate) struct TileResult {
    pub node: VNode,
    pub layer: LayerType,
    pub data: Vec<u8>,
}

pub(crate) struct TileStreamerEndpoint {
    sender: UnboundedSender<TileRequest>,
    receiver: crossbeam::channel::Receiver<TileResult>,
    num_inflight: usize,
}
impl TileStreamerEndpoint {
    pub(crate) fn new(mapfile: Arc<MapFile>) -> Result<Self, Error> {
        let (sender, requests) = unbounded_channel();
        let (results, receiver) = crossbeam::channel::unbounded();

        let rt = Runtime::new()?;
        thread::spawn(move || {
            rt.block_on(async {
                TileStreamer {
                    requests,
                    results,
                    heightmap_tiles: HeightmapCache::new(
                        mapfile.layers()[LayerType::Heightmaps].clone(),
                        32,
                    ),
                    mapfile,
                }
                .run()
                .await
            })
        });

        Ok(Self { sender, receiver, num_inflight: 0 })
    }

    pub(crate) fn request_tile(&mut self, node: VNode, layer: LayerType) {
        self.sender.send(TileRequest { node, layer }).unwrap();
        self.num_inflight += 1;
    }

    pub(crate) fn try_complete(&mut self) -> Option<TileResult> {
        if let Ok(result) = self.receiver.try_recv() {
            self.num_inflight -= 1;
            Some(result)
        } else {
            None
        }
    }

    pub(crate) fn num_inflight(&self) -> usize {
        self.num_inflight
    }
}

struct TileStreamer {
    requests: UnboundedReceiver<TileRequest>,
    results: crossbeam::channel::Sender<TileResult>,
    mapfile: Arc<MapFile>,
    heightmap_tiles: HeightmapCache,
}

impl TileStreamer {
    async fn run(mut self) -> Result<(), Error> {
        let mut pending = futures::stream::futures_unordered::FuturesUnordered::new();

        loop {
            futures::select!{
                request = self.requests.recv().fuse() => if let Some(request) = request {
                    match request.layer {
                        LayerType::Heightmaps => {
                            let fut = self
                                .heightmap_tiles
                                .get_tile(&*self.mapfile, request.node);

                            pending.push(async move {
                                let heights: Vec<_> = fut
                                    .await
                                    .unwrap()
                                    .iter()
                                    .map(|&i| i as f32)
                                    .collect();
                                let mut data = vec![0; heights.len() * 4];
                                data.copy_from_slice(bytemuck::cast_slice(&heights));
                                TileResult { node: request.node, layer: request.layer, data }
                            });
                        }
                        _ => self.results.send(TileResult { node: request.node, layer: request.layer, data: self.mapfile.read_tile(request.layer, request.node).unwrap() })?,
                    }
                },
                tile_result = pending.select_next_some() => {
                    self.results.send(tile_result)?;
                },
                complete => break,
            }
        }
        Ok(())
    }
}
<|endoftext|>