<commit_before>use std::ffi::{CStr,CString};
use std::ptr;
use std::mem;
use std::str;

use libc;
use z3_sys;

pub struct Z3 {
    ctx: z3_sys::Z3_context
}
pub struct Z3Ast<'a> {
    ast: z3_sys::Z3_ast,
    z3: &'a Z3
}
pub struct Z3Sort<'a> {
    sort: z3_sys::Z3_sort,
    z3: &'a Z3
}
pub struct Z3Model<'a> {
    model: *mut z3_sys::Z3_model,
    res: i32,
    z3: &'a Z3
}

macro_rules! impl_mk_1 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, a: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, a.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}
macro_rules! impl_mk_2 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, t1: &Z3Ast, t2: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, t1.ast, t2.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}

impl Z3 {
    pub fn new() -> Z3 {
        unsafe {
            let cfg = z3_sys::Z3_mk_config();
            let ctx = z3_sys::Z3_mk_context(cfg);
            Z3 {
                ctx: ctx
            }
        }
    }
    #[inline]
    pub unsafe fn ctx(&self) -> z3_sys::Z3_context {
        self.ctx
    }
    pub unsafe fn get_model_str(&self, m: z3_sys::Z3_model) -> &str {
        let cstr = z3_sys::Z3_model_to_string(self.ctx, m);
        let slice = CStr::from_ptr(cstr);
        let buf: &[u8] = slice.to_bytes();
        let str_slice: &str = str::from_utf8(buf).unwrap();
        str_slice
    }

    pub fn check_and_get_model<'a>(&'a self, f: &Z3Ast) -> Z3Model<'a> {
        unsafe {
            let mut m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let res = z3_sys::Z3_check_and_get_model(self.ctx, m);

            z3_sys::Z3_pop(self.ctx, 1);

            Z3Model {
                model: m,
                res: res,
                z3: &self
            }
        }
    }

    pub fn prove(&self, f: &Z3Ast, is_valid: bool) {
        unsafe {
            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let mut m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            match z3_sys::Z3_check_and_get_model(self.ctx, m) {
                z3_sys::Z3_L_FALSE => {
                    /* proved */
                    println!("valid\n");
                    if !is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_UNDEF => {
                    /* Z3 failed to prove/disprove f. */
                    println!("unknown\n");
                    if *m != ptr::null_mut() {
                        /* m should be viewed as a potential counterexample. */
                        println!("potential counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_TRUE => {
                    /* disproved */
                    println!("invalid\n");
                    if *m != ptr::null_mut() {
                        /* the model returned by Z3 is a counterexample */
                        println!("counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                _ => panic!("not supported")
            }
            if *m != ptr::null_mut() {
                z3_sys::Z3_del_model(self.ctx, *m);
            }
            z3_sys::Z3_pop(self.ctx(), 1);
        }
    }
    pub fn bv_sort<'a>(&'a self, width: u32) -> Z3Sort<'a> {
        unsafe {
            Z3Sort {
                sort: z3_sys::Z3_mk_bv_sort(self.ctx, width),
                z3: &self
            }
        }
    }

    impl_mk_2!(div, Z3_mk_div);
    impl_mk_2!(od, Z3_mk_mod);
    impl_mk_2!(re, Z3_mk_rem);
    impl_mk_2!(power, Z3_mk_power);
    impl_mk_2!(lt, Z3_mk_lt);
    impl_mk_2!(le, Z3_mk_le);
    impl_mk_2!(gt, Z3_mk_gt);
    impl_mk_2!(ge, Z3_mk_ge);
    impl_mk_2!(bvand, Z3_mk_bvand);
    impl_mk_2!(bvor, Z3_mk_bvor);
    impl_mk_2!(bvxor, Z3_mk_bvxor);
    impl_mk_2!(bvnand, Z3_mk_bvnand);
    impl_mk_2!(bvnor, Z3_mk_bvnor);
    impl_mk_2!(bvxnor, Z3_mk_bvxnor);
    impl_mk_2!(bvadd, Z3_mk_bvadd);
    impl_mk_2!(bvsub, Z3_mk_bvsub);
    impl_mk_2!(bvmul, Z3_mk_bvmul);
    impl_mk_2!(bvudiv, Z3_mk_bvudiv);
    impl_mk_2!(bvsdiv, Z3_mk_bvsdiv);
    impl_mk_2!(bvure, Z3_mk_bvurem);
    impl_mk_2!(bvsre, Z3_mk_bvsrem);
    impl_mk_2!(bvsmod, Z3_mk_bvsmod);
    impl_mk_2!(bvult, Z3_mk_bvult);
    impl_mk_2!(bvslt, Z3_mk_bvslt);
    impl_mk_2!(bvule, Z3_mk_bvule);
    impl_mk_2!(bvsle, Z3_mk_bvsle);
    impl_mk_2!(bvuge, Z3_mk_bvuge);
    impl_mk_2!(bvsge, Z3_mk_bvsge);
    impl_mk_2!(bvugt, Z3_mk_bvugt);
    impl_mk_2!(bvsgt, Z3_mk_bvsgt);
    impl_mk_2!(concat, Z3_mk_concat);
    impl_mk_2!(bvshl, Z3_mk_bvshl);
    impl_mk_2!(bvlshr, Z3_mk_bvlshr);
    impl_mk_2!(bvashr, Z3_mk_bvashr);
    impl_mk_2!(ext_rotate_left, Z3_mk_ext_rotate_left);
    impl_mk_2!(ext_rotate_right, Z3_mk_ext_rotate_right);
    impl_mk_2!(bvadd_no_underflow, Z3_mk_bvadd_no_underflow);
    impl_mk_2!(bvsub_no_overflow, Z3_mk_bvsub_no_overflow);
    impl_mk_2!(bvsdiv_no_overflow, Z3_mk_bvsdiv_no_overflow);
    impl_mk_2!(bvmul_no_underflow, Z3_mk_bvmul_no_underflow);

    impl_mk_1!(not, Z3_mk_not);
    impl_mk_1!(int2real, Z3_mk_int2real);
    impl_mk_1!(real2int, Z3_mk_real2int);
    impl_mk_1!(is_int, Z3_mk_is_int);
    impl_mk_1!(bvnot, Z3_mk_bvnot);
    impl_mk_1!(bvredand, Z3_mk_bvredand);
    impl_mk_1!(bvredor, Z3_mk_bvredor);
    impl_mk_1!(bvneg_no_overflow, Z3_mk_bvneg_no_overflow);
    impl_mk_1!(bvneg, Z3_mk_bvneg);

    pub fn eq<'a>(&'a self, t1: &Z3Ast, t2: &Z3Ast) -> Z3Ast<'a> {
        unsafe {
            let ast = z3_sys::Z3_mk_eq(self.ctx, t1.ast, t2.ast);
            Z3Ast {
                ast: ast,
                z3: &self
            }
        }
    }
}

impl<'a> Z3Sort<'a> {
    pub fn mk_const_i(&'a self, i: i32) -> Z3Ast<'a> {
        unsafe {
            let sym = z3_sys::Z3_mk_int_symbol(self.z3.ctx(), i);
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.z3.ctx(), sym, self.sort),
                z3: self.z3
            }
        }
    }
    pub fn mk_const_str(&'a self, s: &str) -> Z3Ast<'a> {
        unsafe {
            let cs = CString::new(s).unwrap();
            let sym = z3_sys::Z3_mk_string_symbol(self.z3.ctx(), cs.as_ptr());
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.z3.ctx(), sym, self.sort),
                z3: self.z3
            }
        }
    }
}

impl <'a> Z3Ast<'a> {
    pub fn get_u64(&self) -> Option<u64> {
        unsafe {
            let mut res: u64 = 0;
            if z3_sys::Z3_get_numeral_uint64(self.z3.ctx(), self.ast, &mut res)
                == z3_sys::Z3_L_TRUE
            {
                Some(res)
            } else {
                None
            }
        }
    }
}

impl <'a> Z3Model<'a> {
    pub fn eval(&'a self, ast: &Z3Ast) -> Option<Z3Ast<'a>> {
        if self.is_model() {
            unsafe {
                let mut res_ast: z3_sys::Z3_ast = ptr::null_mut();
                if z3_sys::Z3_model_eval(self.z3.ctx(), *self.model,
                                         ast.ast, z3_sys::Z3_L_TRUE,
                                         &mut res_ast) == z3_sys::Z3_L_TRUE {
                    Some(Z3Ast {
                        ast: res_ast,
                        z3: self.z3
                    })
                } else {
                    None
                }
            }
        } else {
            None
        }
    }
    pub fn is_model(&self) -> bool {
        match self.res {
            z3_sys::Z3_L_UNDEF | z3_sys::Z3_L_TRUE => true,
            z3_sys::Z3_L_FALSE => false,
            _ => panic!("not supported")
        }
    }

    pub fn get_str(&self) -> &str {
        if self.is_model() {
                unsafe {
                    let cstr = z3_sys::Z3_model_to_string(self.z3.ctx(), *self.model);
                    let slice = CStr::from_ptr(cstr);
                    let buf: &[u8] = slice.to_bytes();
                    let str_slice: &str = str::from_utf8(buf).unwrap();
                    str_slice
                }
        } else {
            "no model"
        }
    }
}

impl Drop for Z3 {
    fn drop(&mut self) {
        unsafe {
            z3_sys::Z3_del_context(self.ctx);
        }
    }
}

#[test]
fn it_works() {
    let z3 = Z3::new();
    let bv_sorts = z3.bv_sort(32);
    let a = bv_sorts.mk_const_i(1);
    let b = bv_sorts.mk_const_i(2);
    let c = bv_sorts.mk_const_str("c");

    let d = z3.bvand(&a, &b);
    let e = z3.bvor(&a, &b);

    let gt = z3.bvugt(&d, &e);
    let eq = z3.eq(&d, &e);
    let neq = z3.not(&gt);

    let h = z3.prove(&eq, true);

    let model = z3.check_and_get_model(&eq);
    println!("model: {}", model.get_str());

    let new_a = model.eval(&a).unwrap();
    let val_a = new_a.get_u64().unwrap();
    println!("val_a: 0x{:x}", val_a);
}
<commit_msg>removing Z3Sort in favour of Z3 creating the vars/consts directly<commit_after>use std::ffi::{CStr,CString};
use std::ptr;
use std::mem;
use std::str;

use libc;
use z3_sys;

pub struct Z3 {
    ctx: z3_sys::Z3_context
}
#[derive(Clone)]
pub struct Z3Ast<'a> {
    ast: z3_sys::Z3_ast,
    z3: &'a Z3
}
pub struct Z3Model<'a> {
    model: *mut z3_sys::Z3_model,
    res: i32,
    z3: &'a Z3
}

macro_rules! impl_mk_1 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, a: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, a.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}
macro_rules! impl_mk_2 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, t1: &Z3Ast, t2: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, t1.ast, t2.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}

impl Z3 {
    pub fn new() -> Z3 {
        unsafe {
            let cfg = z3_sys::Z3_mk_config();
            let ctx = z3_sys::Z3_mk_context(cfg);
            Z3 {
                ctx: ctx
            }
        }
    }
    #[inline]
    pub unsafe fn ctx(&self) -> z3_sys::Z3_context {
        self.ctx
    }
    pub unsafe fn get_model_str(&self, m: z3_sys::Z3_model) -> &str {
        let cstr = z3_sys::Z3_model_to_string(self.ctx, m);
        let slice = CStr::from_ptr(cstr);
        let buf: &[u8] = slice.to_bytes();
        let str_slice: &str = str::from_utf8(buf).unwrap();
        str_slice
    }

    pub fn check_and_get_model<'a>(&'a self, f: &Z3Ast) -> Z3Model<'a> {
        unsafe {
            let m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let res = z3_sys::Z3_check_and_get_model(self.ctx, m);

            z3_sys::Z3_pop(self.ctx, 1);

            Z3Model {
                model: m,
                res: res,
                z3: &self
            }
        }
    }

    pub fn prove(&self, f: &Z3Ast, is_valid: bool) {
        unsafe {
            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            match z3_sys::Z3_check_and_get_model(self.ctx, m) {
                z3_sys::Z3_L_FALSE => {
                    /* proved */
                    println!("valid\n");
                    if !is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_UNDEF => {
                    /* Z3 failed to prove/disprove f. */
                    println!("unknown\n");
                    if *m != ptr::null_mut() {
                        /* m should be viewed as a potential counterexample. */
                        println!("potential counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_TRUE => {
                    /* disproved */
                    println!("invalid\n");
                    if *m != ptr::null_mut() {
                        /* the model returned by Z3 is a counterexample */
                        println!("counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                _ => panic!("not supported")
            }
            if *m != ptr::null_mut() {
                z3_sys::Z3_del_model(self.ctx, *m);
            }
            z3_sys::Z3_pop(self.ctx(), 1);
        }
    }

    impl_mk_2!(div, Z3_mk_div);
    impl_mk_2!(od, Z3_mk_mod);
    impl_mk_2!(re, Z3_mk_rem);
    impl_mk_2!(power, Z3_mk_power);
    impl_mk_2!(lt, Z3_mk_lt);
    impl_mk_2!(le, Z3_mk_le);
    impl_mk_2!(gt, Z3_mk_gt);
    impl_mk_2!(ge, Z3_mk_ge);
    impl_mk_2!(bvand, Z3_mk_bvand);
    impl_mk_2!(bvor, Z3_mk_bvor);
    impl_mk_2!(bvxor, Z3_mk_bvxor);
    impl_mk_2!(bvnand, Z3_mk_bvnand);
    impl_mk_2!(bvnor, Z3_mk_bvnor);
    impl_mk_2!(bvxnor, Z3_mk_bvxnor);
    impl_mk_2!(bvadd, Z3_mk_bvadd);
    impl_mk_2!(bvsub, Z3_mk_bvsub);
    impl_mk_2!(bvmul, Z3_mk_bvmul);
    impl_mk_2!(bvudiv, Z3_mk_bvudiv);
    impl_mk_2!(bvsdiv, Z3_mk_bvsdiv);
    impl_mk_2!(bvure, Z3_mk_bvurem);
    impl_mk_2!(bvsre, Z3_mk_bvsrem);
    impl_mk_2!(bvsmod, Z3_mk_bvsmod);
    impl_mk_2!(bvult, Z3_mk_bvult);
    impl_mk_2!(bvslt, Z3_mk_bvslt);
    impl_mk_2!(bvule, Z3_mk_bvule);
    impl_mk_2!(bvsle, Z3_mk_bvsle);
    impl_mk_2!(bvuge, Z3_mk_bvuge);
    impl_mk_2!(bvsge, Z3_mk_bvsge);
    impl_mk_2!(bvugt, Z3_mk_bvugt);
    impl_mk_2!(bvsgt, Z3_mk_bvsgt);
    impl_mk_2!(concat, Z3_mk_concat);
    impl_mk_2!(bvshl, Z3_mk_bvshl);
    impl_mk_2!(bvlshr, Z3_mk_bvlshr);
    impl_mk_2!(bvashr, Z3_mk_bvashr);
    impl_mk_2!(ext_rotate_left, Z3_mk_ext_rotate_left);
    impl_mk_2!(ext_rotate_right, Z3_mk_ext_rotate_right);
    impl_mk_2!(bvadd_no_underflow, Z3_mk_bvadd_no_underflow);
    impl_mk_2!(bvsub_no_overflow, Z3_mk_bvsub_no_overflow);
    impl_mk_2!(bvsdiv_no_overflow, Z3_mk_bvsdiv_no_overflow);
    impl_mk_2!(bvmul_no_underflow, Z3_mk_bvmul_no_underflow);

    impl_mk_1!(not, Z3_mk_not);
    impl_mk_1!(int2real, Z3_mk_int2real);
    impl_mk_1!(real2int, Z3_mk_real2int);
    impl_mk_1!(is_int, Z3_mk_is_int);
    impl_mk_1!(bvnot, Z3_mk_bvnot);
    impl_mk_1!(bvredand, Z3_mk_bvredand);
    impl_mk_1!(bvredor, Z3_mk_bvredor);
    impl_mk_1!(bvneg_no_overflow, Z3_mk_bvneg_no_overflow);
    impl_mk_1!(bvneg, Z3_mk_bvneg);

    pub fn eq<'a>(&'a self, t1: &Z3Ast, t2: &Z3Ast) -> Z3Ast<'a> {
        unsafe {
            let ast = z3_sys::Z3_mk_eq(self.ctx, t1.ast, t2.ast);
            Z3Ast {
                ast: ast,
                z3: &self
            }
        }
    }

    /// Create a new BitVector const of name `i` and width `w`
    pub fn mk_bv_i<'a>(&'a self, i: i32, w: u32) -> Z3Ast<'a> {
        unsafe {
            let sort= z3_sys::Z3_mk_bv_sort(self.ctx, w);
            let sym = z3_sys::Z3_mk_int_symbol(self.ctx, i);
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.ctx, sym, sort),
                z3: &self
            }
        }
    }
    /// Create a new BitVector const of name `s` and width `w`
    pub fn mk_bv_str<'a>(&'a self, s: &str, w: u32) -> Z3Ast<'a> {
        unsafe {
            let sort= z3_sys::Z3_mk_bv_sort(self.ctx, w);
            let cs = CString::new(s).unwrap();
            let sym = z3_sys::Z3_mk_string_symbol(self.ctx, cs.as_ptr());
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.ctx, sym, sort),
                z3: &self
            }
        }
    }

}

impl <'a> Z3Ast<'a> {
    pub fn get_u64(&self) -> Option<u64> {
        unsafe {
            let mut res: u64 = 0;
            if z3_sys::Z3_get_numeral_uint64(self.z3.ctx(), self.ast, &mut res)
                == z3_sys::Z3_L_TRUE
            {
                Some(res)
            } else {
                None
            }
        }
    }
}

impl <'a> Z3Model<'a> {
    pub fn eval(&'a self, ast: &Z3Ast) -> Option<Z3Ast<'a>> {
        if self.is_model() {
            unsafe {
                let mut res_ast: z3_sys::Z3_ast = ptr::null_mut();
                if z3_sys::Z3_model_eval(self.z3.ctx(), *self.model,
                                         ast.ast, z3_sys::Z3_L_TRUE,
                                         &mut res_ast) == z3_sys::Z3_L_TRUE {
                    Some(Z3Ast {
                        ast: res_ast,
                        z3: self.z3
                    })
                } else {
                    None
                }
            }
        } else {
            None
        }
    }
    pub fn is_model(&self) -> bool {
        match self.res {
            z3_sys::Z3_L_UNDEF | z3_sys::Z3_L_TRUE => true,
            z3_sys::Z3_L_FALSE => false,
            _ => panic!("not supported")
        }
    }

    pub fn get_str(&self) -> &str {
        if self.is_model() {
                unsafe {
                    let cstr = z3_sys::Z3_model_to_string(self.z3.ctx(), *self.model);
                    let slice = CStr::from_ptr(cstr);
                    let buf: &[u8] = slice.to_bytes();
                    let str_slice: &str = str::from_utf8(buf).unwrap();
                    str_slice
                }
        } else {
            "no model"
        }
    }
}

impl Drop for Z3 {
    fn drop(&mut self) {
        unsafe {
            z3_sys::Z3_del_context(self.ctx);
        }
    }
}

#[test]
fn it_works() {
    let z3 = Z3::new();
    let a = z3.mk_bv_i(1, 32);
    let b = z3.mk_bv_i(2, 32);
    let c = z3.mk_bv_str("c", 32);

    let d = z3.bvand(&a, &b);
    let e = z3.bvor(&a, &b);

    let gt = z3.bvugt(&d, &e);
    let eq = z3.eq(&d, &e);
    let neq = z3.not(&gt);

    let h = z3.prove(&eq, true);

    let model = z3.check_and_get_model(&eq);
    println!("model: {}", model.get_str());

    let new_a = model.eval(&a).unwrap();
    let val_a = new_a.get_u64().unwrap();
    println!("val_a: 0x{:x}", val_a);
}
<|endoftext|>


<commit_before>use hyper;
use iron::prelude::{IronError, IronResult, Request, Response};
use iron::status;
use iron::typemap::Key;
use persistent;
use persistent::State;
use postgres;
use postgres::error::SqlState;
use potboiler_common::{db, url_from_body};
use potboiler_common::string_error::StringError;

use r2d2;
use r2d2_postgres;
use serde_json;
use serde_types::Log;
use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::iter::FromIterator;

use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use url::Url;
use uuid::Uuid;
pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPool = r2d2::Pool<r2d2_postgres::PostgresConnectionManager>;
use clock;
use hybrid_clocks::{Clock, Timestamp, Wall, WallT};
use std::sync::RwLock;
pub type SyncClock = Arc<RwLock<Clock<Wall>>>;
pub type LockedNode = Arc<RwLock<HashMap<String, NodeInfo>>>;

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

pub struct NodeInfo {
}

#[derive(Clone)]
pub struct NodeList {
    nodes: LockedNode,
    pool: PostgresPool,
    clock: SyncClock,
}

impl Key for Nodes {
    type Value = NodeList;
}

fn parse_json_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                           -> Result<serde_json::value::Value, StringError> {
    let mut res = match raw_result {
        Ok(val) => val,
        Err(val) => {
            return Err(StringError(format!("Failed to get logs: {:?}", val)));
        }
    };
    let body_string = {
        let mut body = String::new();
        res.read_to_string(&mut body).expect("could read from body");
        body
    };
    return match serde_json::de::from_str(&body_string) {
        Ok(val) => {
            debug!("Good data back {:?}", val);
            Ok(val)
        }
        Err(_) => Err(StringError(format!("Got crappy data back: {:?}", body_string))),
    };
}

fn parse_object_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                             -> Result<serde_json::value::Map<String, serde_json::Value>, StringError> {
    let json: serde_json::Value = match parse_json_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => return Err(err),
    };
    return match json.as_object() {
        Some(val) => Ok(val.clone()),
        None => Err(StringError(format!("Info isn't a map: {:?}", json))),
    };
}

fn check_host_once(host_url: &String, conn: &PostgresConnection, clock_state: SyncClock) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/log", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let kv = match parse_object_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {:?}: {:?}", host_url, err);
            return;
        }
    };
    let stmt = conn.prepare("SELECT 1 from log where id=$1")
        .expect("prepare failure");
    for (key, value) in kv.iter() {
        let value_uuid = match Uuid::parse_str(value.as_str().unwrap()) {
            Ok(val) => val,
            Err(_) => {
                warn!("Value {} isn't a UUID!", value);
                continue;
            }
        };
        let key_uuid = match Uuid::parse_str(key) {
            Ok(val) => val,
            Err(_) => {
                warn!("Key {} isn't a UUID!", key);
                continue;
            }
        };
        let single_item = stmt.query(&[&value_uuid]).expect("bad single query");
        if !single_item.is_empty() {
            debug!("Already have {} locally", value_uuid);
            continue;
        }

        let first_item = conn.query("SELECT id from log WHERE prev is null and owner=$1 limit 1",
                   &[&key_uuid])
            .expect("bad first query");
        let start_uuid = if first_item.is_empty() {
            let first_url = format!("{}/log/first", &host_url);
            debug!("Get first from {:?}", host_url);
            let res = client.get(&first_url).send();
            let first_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("First entry: {:?}", first_entry);
            first_entry.get(key).unwrap().clone()
        } else {
            info!("Already have an entry from the list with server id {:?}",
                  key);
            let last_items = conn.query("SELECT id from log WHERE next is null and owner=$1 limit 1",
                       &[&key_uuid])
                .expect("bad last query");
            if last_items.is_empty() {
                warn!("Can't find end entry for server id {:?}", key);
                return;
            }
            let last_item = last_items.get(0);
            let last_item_id: Uuid = last_item.get("id");
            info!("Last item: {:?}", last_item_id);
            let last_url = format!("{}/log/{}", &host_url, last_item_id);
            debug!("Get last from {:?}", host_url);
            let res = client.get(&last_url).send();
            let last_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("Last entry: {:?}", last_entry);
            last_entry.get("next").unwrap().clone()
        };
        let mut current_uuid = start_uuid;
        loop {
            let real_uuid = {
                let str_uuid = current_uuid.as_str();
                String::from(str_uuid.expect("UUID unwrap"))
            };
            let current_url = format!("{}/log/{}", &host_url, real_uuid);
            debug!("Get {} from {}", real_uuid, host_url);
            let res = client.get(&current_url).send();
            let current_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            let next = current_entry.get("next").expect("has next key");
            let timestamp: Timestamp<WallT> =
                serde_json::value::from_value(current_entry.get("when").expect(" has when key").clone())
                    .expect("is byte string");
            clock::observe_timestamp(&clock_state, timestamp);
            let log = Log {
                id: Uuid::parse_str(&real_uuid).unwrap(),
                owner: key_uuid,
                next: get_uuid_from_map(&current_entry, "next"),
                prev: get_uuid_from_map(&current_entry, "prev"),
                data: current_entry.get("data").unwrap().clone(),
                when: clock::get_timestamp_from_state(&clock_state),
            };
            insert_log(conn, &log);
            if next.is_null() {
                break;
            }
            current_uuid = next.clone();
        }
    }
}

fn get_uuid_from_map(map: &serde_json::value::Map<String, serde_json::Value>, key: &str) -> Option<Uuid> {
    let value = map.get(key).unwrap();
    if value.is_null() {
        None
    } else {
        Some(Uuid::parse_str(value.as_str().unwrap()).unwrap())
    }
}

pub fn insert_log(conn: &PostgresConnection, log: &Log) {
    debug!("Inserting {:?}", log);
    if log.prev.is_some() {
        conn.execute("UPDATE log set next = $1 where owner = $2 and id = $3",
                     &[&log.id, &log.owner, &log.prev])
            .expect("update worked");
    }
    let raw_timestamp = clock::get_raw_timestamp(&log.when);
    conn.execute("INSERT INTO log (id, owner, data, prev, hlc_tstamp) VALUES ($1, $2, $3, $4, $5)",
                 &[&log.id, &log.owner, &log.data, &log.prev, &raw_timestamp])
        .expect("insert worked");
}

fn check_new_nodes(host_url: &String, conn: &PostgresConnection, nodelist: NodeList) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/nodes", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let remote_nodes = match parse_json_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {:?}: {:?}", host_url, err);
            return;
        }
    };
    let remote_node_set: HashSet<String> = HashSet::from_iter(remote_nodes.as_array()
        .unwrap()
        .iter()
        .map(|x| String::from(x.as_str().unwrap())));
    let existing_nodes = conn.query("SELECT url from nodes", &[])
        .expect("prepare failure");
    let existing_nodes_set: HashSet<String> = HashSet::from_iter(existing_nodes.iter()
        .map(|x| x.get::<&str, String>("url")));
    let extra_nodes = remote_node_set.difference(&existing_nodes_set)
        .map(|x| x.clone())
        .collect::<Vec<String>>();
    debug!("existing nodes: {:?}; remote nodes: {:?}",
           existing_nodes_set,
           remote_node_set);
    info!("extra nodes: {:?}", extra_nodes);
    let mut nodes = nodelist.nodes.write().unwrap();
    for extra in extra_nodes {
        nodes.insert(extra.clone(), NodeInfo {});
        let nodeslist = nodelist.clone();
        thread::spawn(move || check_host(extra.clone(), nodeslist));
    }
}

fn check_host(host_url: String, nodelist: NodeList) {
    let sleep_time = Duration::from_secs(5);
    let conn = nodelist.pool.get().unwrap();
    loop {
        check_host_once(&host_url, &conn, nodelist.clock.clone());
        check_new_nodes(&host_url, &conn, nodelist.clone());
        thread::sleep(sleep_time);
    }
}

pub fn initial_nodes(pool: PostgresPool, clock_state: SyncClock) -> NodeList {
    let conn = pool.get().unwrap();
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    let locked_nodes = Arc::new(RwLock::new(HashMap::new()));
    let mut nodes = locked_nodes.write().unwrap();
    for row in &stmt.query(&[]).expect("nodes select works") {
        let url: String = row.get("url");
        nodes.insert(url.clone(), NodeInfo {});
        let nodeslist = NodeList {
            nodes: locked_nodes.clone(),
            pool: pool.clone(),
            clock: clock_state.clone(),
        };
        thread::spawn(move || check_host(url.clone(), nodeslist));
    }
    return NodeList {
        nodes: locked_nodes.clone(),
        pool: pool,
        clock: clock_state,
    };
}

fn get_nodes_list(req: &Request) -> Vec<String> {
    let state_ref = req.extensions.get::<State<Nodes>>().unwrap().read().unwrap();
    let nodes = state_ref.deref().nodes.read().unwrap();
    let mut vec = Vec::with_capacity(nodes.len());
    for key in nodes.keys() {
        vec.push(key.clone());
    }
    return vec;
}

fn insert_node(req: &mut Request, to_notify: &String) {
    let nodelist = {
        let mut nodelist = req.extensions
            .get_mut::<State<Nodes>>()
            .unwrap()
            .write()
            .unwrap();
        let nodelist_dm = nodelist.deref_mut();
        nodelist_dm.nodes.write().unwrap().insert(to_notify.clone(), NodeInfo {});
        NodeList {
            nodes: nodelist_dm.nodes.clone(),
            pool: nodelist_dm.pool.clone(),
            clock: nodelist_dm.clock.clone(),
        }
    };

    let url = to_notify.clone();
    thread::spawn(move || check_host(url, nodelist));
}

pub fn notify_everyone(req: &Request, log_arc: Arc<Log>) {
    let nodes = get_nodes_list(req);
    for node in nodes {
        let local_log = log_arc.clone();
        thread::spawn(move || {
            let client = hyper::client::Client::new();
            let notify_url = format!("{}/log/other", node);
            debug!("Notifying (node) {}", notify_url);
            let res = client.post(&notify_url)
                .body(&serde_json::ser::to_string(&local_log).unwrap())
                .send();
            match res {
                Ok(val) => {
                    if val.status != hyper::status::StatusCode::Ok {
                        warn!("Failed to notify {:?}: {:?}", &node, val.status);
                    }
                }
                Err(val) => {
                    warn!("Failed to notify {:?}: {:?}", &node, val);
                }
            };
        });
    }
}

pub fn node_add(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering node {}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute("INSERT INTO nodes (url) VALUES ($1)", &[&url]) {
                Ok(_) => {
                    insert_node(req, &url);
                    Ok(Response::with((status::NoContent)))
                }
                Err(err) => {
                    if let postgres::error::Error::Db(dberr) = err {
                        match dberr.code {
                            SqlState::UniqueViolation => Ok(Response::with((status::NoContent))),
                            _ => Err(IronError::new(dberr, (status::BadRequest, "Some other error"))),
                        }
                    } else {
                        Err(IronError::new(err, (status::BadRequest, "Some other error")))
                    }
                }
            }
        }
    }
}

pub fn node_remove(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    conn.execute("DELETE from nodes where url = $1",
                 &[&url_from_body(req).unwrap().unwrap()])
        .expect("delete worked");
    Ok(Response::with((status::NoContent)))
}

pub fn node_list(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    let mut nodes = Vec::new();
    for row in &stmt.query(&[]).expect("last select works") {
        let url: String = row.get("url");
        nodes.push(url);
    }
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&nodes).unwrap())))
}
<commit_msg>Actually insert new discovered nodes<commit_after>use hyper;
use iron::prelude::{IronError, IronResult, Request, Response};
use iron::status;
use iron::typemap::Key;
use persistent;
use persistent::State;
use postgres;
use postgres::error::SqlState;
use potboiler_common::{db, url_from_body};
use potboiler_common::string_error::StringError;

use r2d2;
use r2d2_postgres;
use serde_json;
use serde_types::Log;
use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::iter::FromIterator;

use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use url::Url;
use uuid::Uuid;
pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPool = r2d2::Pool<r2d2_postgres::PostgresConnectionManager>;
use clock;
use hybrid_clocks::{Clock, Timestamp, Wall, WallT};
use std::sync::RwLock;
pub type SyncClock = Arc<RwLock<Clock<Wall>>>;
pub type LockedNode = Arc<RwLock<HashMap<String, NodeInfo>>>;

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

pub struct NodeInfo {
}

#[derive(Clone)]
pub struct NodeList {
    nodes: LockedNode,
    pool: PostgresPool,
    clock: SyncClock,
}

impl Key for Nodes {
    type Value = NodeList;
}

fn parse_json_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                           -> Result<serde_json::value::Value, StringError> {
    let mut res = match raw_result {
        Ok(val) => val,
        Err(val) => {
            return Err(StringError(format!("Failed to get logs: {:?}", val)));
        }
    };
    let body_string = {
        let mut body = String::new();
        res.read_to_string(&mut body).expect("could read from body");
        body
    };
    return match serde_json::de::from_str(&body_string) {
        Ok(val) => {
            debug!("Good data back {:?}", val);
            Ok(val)
        }
        Err(_) => Err(StringError(format!("Got crappy data back: {:?}", body_string))),
    };
}

fn parse_object_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                             -> Result<serde_json::value::Map<String, serde_json::Value>, StringError> {
    let json: serde_json::Value = match parse_json_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => return Err(err),
    };
    return match json.as_object() {
        Some(val) => Ok(val.clone()),
        None => Err(StringError(format!("Info isn't a map: {:?}", json))),
    };
}

fn check_host_once(host_url: &String, conn: &PostgresConnection, clock_state: SyncClock) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/log", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let kv = match parse_object_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {:?}: {:?}", host_url, err);
            return;
        }
    };
    let stmt = conn.prepare("SELECT 1 from log where id=$1")
        .expect("prepare failure");
    for (key, value) in kv.iter() {
        let value_uuid = match Uuid::parse_str(value.as_str().unwrap()) {
            Ok(val) => val,
            Err(_) => {
                warn!("Value {} isn't a UUID!", value);
                continue;
            }
        };
        let key_uuid = match Uuid::parse_str(key) {
            Ok(val) => val,
            Err(_) => {
                warn!("Key {} isn't a UUID!", key);
                continue;
            }
        };
        let single_item = stmt.query(&[&value_uuid]).expect("bad single query");
        if !single_item.is_empty() {
            debug!("Already have {} locally", value_uuid);
            continue;
        }

        let first_item = conn.query("SELECT id from log WHERE prev is null and owner=$1 limit 1",
                   &[&key_uuid])
            .expect("bad first query");
        let start_uuid = if first_item.is_empty() {
            let first_url = format!("{}/log/first", &host_url);
            debug!("Get first from {:?}", host_url);
            let res = client.get(&first_url).send();
            let first_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("First entry: {:?}", first_entry);
            first_entry.get(key).unwrap().clone()
        } else {
            info!("Already have an entry from the list with server id {:?}",
                  key);
            let last_items = conn.query("SELECT id from log WHERE next is null and owner=$1 limit 1",
                       &[&key_uuid])
                .expect("bad last query");
            if last_items.is_empty() {
                warn!("Can't find end entry for server id {:?}", key);
                return;
            }
            let last_item = last_items.get(0);
            let last_item_id: Uuid = last_item.get("id");
            info!("Last item: {:?}", last_item_id);
            let last_url = format!("{}/log/{}", &host_url, last_item_id);
            debug!("Get last from {:?}", host_url);
            let res = client.get(&last_url).send();
            let last_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("Last entry: {:?}", last_entry);
            last_entry.get("next").unwrap().clone()
        };
        let mut current_uuid = start_uuid;
        loop {
            let real_uuid = {
                let str_uuid = current_uuid.as_str();
                String::from(str_uuid.expect("UUID unwrap"))
            };
            let current_url = format!("{}/log/{}", &host_url, real_uuid);
            debug!("Get {} from {}", real_uuid, host_url);
            let res = client.get(&current_url).send();
            let current_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            let next = current_entry.get("next").expect("has next key");
            let timestamp: Timestamp<WallT> =
                serde_json::value::from_value(current_entry.get("when").expect(" has when key").clone())
                    .expect("is byte string");
            clock::observe_timestamp(&clock_state, timestamp);
            let log = Log {
                id: Uuid::parse_str(&real_uuid).unwrap(),
                owner: key_uuid,
                next: get_uuid_from_map(&current_entry, "next"),
                prev: get_uuid_from_map(&current_entry, "prev"),
                data: current_entry.get("data").unwrap().clone(),
                when: clock::get_timestamp_from_state(&clock_state),
            };
            insert_log(conn, &log);
            if next.is_null() {
                break;
            }
            current_uuid = next.clone();
        }
    }
}

fn get_uuid_from_map(map: &serde_json::value::Map<String, serde_json::Value>, key: &str) -> Option<Uuid> {
    let value = map.get(key).unwrap();
    if value.is_null() {
        None
    } else {
        Some(Uuid::parse_str(value.as_str().unwrap()).unwrap())
    }
}

pub fn insert_log(conn: &PostgresConnection, log: &Log) {
    debug!("Inserting {:?}", log);
    if log.prev.is_some() {
        conn.execute("UPDATE log set next = $1 where owner = $2 and id = $3",
                     &[&log.id, &log.owner, &log.prev])
            .expect("update worked");
    }
    let raw_timestamp = clock::get_raw_timestamp(&log.when);
    conn.execute("INSERT INTO log (id, owner, data, prev, hlc_tstamp) VALUES ($1, $2, $3, $4, $5)",
                 &[&log.id, &log.owner, &log.data, &log.prev, &raw_timestamp])
        .expect("insert worked");
}

fn check_new_nodes(host_url: &String, conn: &PostgresConnection, nodelist: NodeList) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/nodes", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let remote_nodes = match parse_json_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {}: {:?}", host_url, err);
            return;
        }
    };
    let remote_node_set: HashSet<String> = HashSet::from_iter(remote_nodes.as_array()
        .unwrap()
        .iter()
        .map(|x| String::from(x.as_str().unwrap())));
    let existing_nodes = conn.query("SELECT url from nodes", &[])
        .expect("prepare failure");
    let existing_nodes_set: HashSet<String> = HashSet::from_iter(existing_nodes.iter()
        .map(|x| x.get::<&str, String>("url")));
    let extra_nodes = remote_node_set.difference(&existing_nodes_set)
        .map(|x| x.clone())
        .collect::<Vec<String>>();
    debug!("From {} remote nodes: {:?}", check_url, remote_node_set);
    info!("Extra nodes from {}: {:?}", check_url, extra_nodes);
    let mut nodes = nodelist.nodes.write().unwrap();
    for extra in extra_nodes {
        match node_insert(&conn, &extra) {
            InsertResult::Inserted => {
                nodes.insert(extra.clone(), NodeInfo {});
                let nodeslist = nodelist.clone();
                thread::spawn(move || check_host(extra.clone(), nodeslist));
            }
            InsertResult::Existing => {}
            InsertResult::Error(err) => {
                warn!("Error while inserting node: {:?}", err);
            }
        }
    }
}

fn check_host(host_url: String, nodelist: NodeList) {
    let sleep_time = Duration::from_secs(5);
    let conn = nodelist.pool.get().unwrap();
    loop {
        check_host_once(&host_url, &conn, nodelist.clock.clone());
        check_new_nodes(&host_url, &conn, nodelist.clone());
        thread::sleep(sleep_time);
    }
}

pub fn initial_nodes(pool: PostgresPool, clock_state: SyncClock) -> NodeList {
    let conn = pool.get().unwrap();
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    let locked_nodes = Arc::new(RwLock::new(HashMap::new()));
    let mut nodes = locked_nodes.write().unwrap();
    for row in &stmt.query(&[]).expect("nodes select works") {
        let url: String = row.get("url");
        nodes.insert(url.clone(), NodeInfo {});
        let nodeslist = NodeList {
            nodes: locked_nodes.clone(),
            pool: pool.clone(),
            clock: clock_state.clone(),
        };
        thread::spawn(move || check_host(url.clone(), nodeslist));
    }
    return NodeList {
        nodes: locked_nodes.clone(),
        pool: pool,
        clock: clock_state,
    };
}

fn get_nodes_list(req: &Request) -> Vec<String> {
    let state_ref = req.extensions.get::<State<Nodes>>().unwrap().read().unwrap();
    let nodes = state_ref.deref().nodes.read().unwrap();
    let mut vec = Vec::with_capacity(nodes.len());
    for key in nodes.keys() {
        vec.push(key.clone());
    }
    return vec;
}

fn insert_node(req: &mut Request, to_notify: &String) {
    let nodelist = {
        let mut nodelist = req.extensions
            .get_mut::<State<Nodes>>()
            .unwrap()
            .write()
            .unwrap();
        let nodelist_dm = nodelist.deref_mut();
        nodelist_dm.nodes.write().unwrap().insert(to_notify.clone(), NodeInfo {});
        NodeList {
            nodes: nodelist_dm.nodes.clone(),
            pool: nodelist_dm.pool.clone(),
            clock: nodelist_dm.clock.clone(),
        }
    };

    let url = to_notify.clone();
    thread::spawn(move || check_host(url, nodelist));
}

pub fn notify_everyone(req: &Request, log_arc: Arc<Log>) {
    let nodes = get_nodes_list(req);
    for node in nodes {
        let local_log = log_arc.clone();
        thread::spawn(move || {
            let client = hyper::client::Client::new();
            let notify_url = format!("{}/log/other", node);
            debug!("Notifying (node) {}", notify_url);
            let res = client.post(&notify_url)
                .body(&serde_json::ser::to_string(&local_log).unwrap())
                .send();
            match res {
                Ok(val) => {
                    if val.status != hyper::status::StatusCode::Ok {
                        warn!("Failed to notify {:?}: {:?}", &node, val.status);
                    }
                }
                Err(val) => {
                    warn!("Failed to notify {:?}: {:?}", &node, val);
                }
            };
        });
    }
}

enum InsertResult {
    Inserted,
    Existing,
    Error(postgres::error::Error),
}

fn node_insert(conn: &PostgresConnection, url: &String) -> InsertResult {
    return match conn.execute("INSERT INTO nodes (url) VALUES ($1)", &[&url]) {
        Ok(_) => InsertResult::Inserted,
        Err(err) => {
            if let postgres::error::Error::Db(dberr) = err {
                match dberr.code {
                    SqlState::UniqueViolation => InsertResult::Existing,
                    _ => InsertResult::Error(postgres::error::Error::Db(dberr)),
                }
            } else {
                InsertResult::Error(err)
            }
        }
    };
}

pub fn node_add(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering node {}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match node_insert(&conn, &url) {
                InsertResult::Inserted => {
                    insert_node(req, &url);
                    Ok(Response::with((status::NoContent)))
                }
                InsertResult::Existing => Ok(Response::with((status::NoContent))),
                InsertResult::Error(err) => {
                    Err(IronError::new(err, (status::BadRequest, "Some other error")))
                }
            }
        }
    }
}

pub fn node_remove(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    conn.execute("DELETE from nodes where url = $1",
                 &[&url_from_body(req).unwrap().unwrap()])
        .expect("delete worked");
    Ok(Response::with((status::NoContent)))
}

pub fn node_list(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    let mut nodes = Vec::new();
    for row in &stmt.query(&[]).expect("last select works") {
        let url: String = row.get("url");
        nodes.push(url);
    }
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&nodes).unwrap())))
}
<|endoftext|>


<commit_before>use hyper;
use iron::prelude::{IronError, IronResult, Request, Response};
use iron::status;
use iron::typemap::Key;
use persistent;
use persistent::State;
use postgres;
use postgres::error::SqlState;
use potboiler_common::{db, url_from_body};
use potboiler_common::string_error::StringError;

use r2d2;
use r2d2_postgres;
use serde_json;
use serde_types::Log;
use std::collections::HashMap;
use std::io::Read;

use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use url::Url;
use uuid::Uuid;
pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPool = r2d2::Pool<r2d2_postgres::PostgresConnectionManager>;
use clock;
use hybrid_clocks::{Timestamp, WallT, Wall, Clock};
use std::sync::RwLock;
pub type SyncClock = Arc<RwLock<Clock<Wall>>>;

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

pub struct NodeInfo {
}

pub struct NodeList {
    nodes: HashMap<String, NodeInfo>,
    pool: PostgresPool,
    clock: SyncClock,
}

impl Key for Nodes {
    type Value = NodeList;
}

fn parse_object_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                             -> Result<serde_json::value::Map<String, serde_json::Value>, StringError> {
    let mut res = match raw_result {
        Ok(val) => val,
        Err(val) => {
            return Err(StringError(format!("Failed to get logs: {:?}", val)));
        }
    };
    let body_string = {
        let mut body = String::new();
        res.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: serde_json::Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => {
            debug!("Good data back {:?}", val);
            val
        }
        Err(_) => return Err(StringError(format!("Got crappy data back: {:?}", body_string))),
    };
    return match json.as_object() {
        Some(val) => Ok(val.clone()),
        None => Err(StringError(format!("Info isn't a map: {:?}", json))),
    };
}

fn check_host_once(host_url: &String, conn: &PostgresConnection, clock_state: SyncClock) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/log", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let kv = match parse_object_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {:?}: {:?}", host_url, err);
            return;
        }
    };
    let stmt = conn.prepare("SELECT 1 from log where id=$1")
        .expect("prepare failure");
    for (key, value) in kv.iter() {
        let value_uuid = match Uuid::parse_str(value.as_str().unwrap()) {
            Ok(val) => val,
            Err(_) => {
                warn!("Value {} isn't a UUID!", value);
                continue;
            }
        };
        let key_uuid = match Uuid::parse_str(key) {
            Ok(val) => val,
            Err(_) => {
                warn!("Key {} isn't a UUID!", key);
                continue;
            }
        };
        let single_item = stmt.query(&[&value_uuid]).expect("bad single query");
        if !single_item.is_empty() {
            debug!("Already have {} locally", value_uuid);
            continue;
        }

        let first_item = conn.query("SELECT id from log WHERE prev is null and owner=$1 limit 1",
                   &[&key_uuid])
            .expect("bad first query");
        let start_uuid = if first_item.is_empty() {
            let first_url = format!("{}/log/first", &host_url);
            debug!("Get first from {:?}", host_url);
            let res = client.get(&first_url).send();
            let first_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("First entry: {:?}", first_entry);
            first_entry.get(key).unwrap().clone()
        } else {
            info!("Already have an entry from the list with server id {:?}",
                  key);
            let last_items = conn.query("SELECT id from log WHERE next is null and owner=$1 limit 1",
                       &[&key_uuid])
                .expect("bad last query");
            if last_items.is_empty() {
                warn!("Can't find end entry for server id {:?}", key);
                return;
            }
            let last_item = last_items.get(0);
            let last_item_id: Uuid = last_item.get("id");
            info!("Last item: {:?}", last_item_id);
            let last_url = format!("{}/log/{}", &host_url, last_item_id);
            debug!("Get last from {:?}", host_url);
            let res = client.get(&last_url).send();
            let last_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("Last entry: {:?}", last_entry);
            last_entry.get("next").unwrap().clone()
        };
        let mut current_uuid = start_uuid;
        loop {
            let real_uuid = {
                let str_uuid = current_uuid.as_str();
                String::from(str_uuid.expect("UUID unwrap"))
            };
            let current_url = format!("{}/log/{}", &host_url, real_uuid);
            debug!("Get {} from {}", real_uuid, host_url);
            let res = client.get(&current_url).send();
            let current_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            let next = current_entry.get("next").expect("has next key");
            let timestamp: Timestamp<WallT> =
                serde_json::value::from_value(current_entry.get("when").expect(" has when key").clone())
                    .expect("is byte string");
            clock::observe_timestamp(&clock_state, timestamp);
            let log = Log {
                id: Uuid::parse_str(&real_uuid).unwrap(),
                owner: key_uuid,
                next: get_uuid_from_map(&current_entry, "next"),
                prev: get_uuid_from_map(&current_entry, "prev"),
                data: current_entry.get("data").unwrap().clone(),
                when: clock::get_timestamp_from_state(&clock_state),
            };
            insert_log(conn, &log);
            if next.is_null() {
                break;
            }
            current_uuid = next.clone();
        }
    }
}

fn get_uuid_from_map(map: &serde_json::value::Map<String, serde_json::Value>, key: &str) -> Option<Uuid> {
    let value = map.get(key).unwrap();
    if value.is_null() {
        None
    } else {
        Some(Uuid::parse_str(value.as_str().unwrap()).unwrap())
    }
}

pub fn insert_log(conn: &PostgresConnection, log: &Log) {
    debug!("Inserting {:?}", log);
    if log.prev.is_some() {
        conn.execute("UPDATE log set next = $1 where owner = $2 and id = $3",
                     &[&log.id, &log.owner, &log.prev])
            .expect("update worked");
    }
    let raw_timestamp = clock::get_raw_timestamp(&log.when);
    conn.execute("INSERT INTO log (id, owner, data, prev, hlc_tstamp) VALUES ($1, $2, $3, $4, $5)",
                 &[&log.id, &log.owner, &log.data, &log.prev, &raw_timestamp])
        .expect("insert worked");
}

fn check_host(host_url: String, conn: PostgresConnection, clock_state: SyncClock) {
    let sleep_time = Duration::from_secs(5);
    loop {
        check_host_once(&host_url, &conn, clock_state.clone());
        thread::sleep(sleep_time);
    }
}

pub fn initial_nodes(pool: PostgresPool, clock_state: SyncClock) -> NodeList {
    let conn = pool.get().unwrap();
    let mut nodes = HashMap::new();
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    for row in &stmt.query(&[]).expect("nodes select works") {
        let url: String = row.get("url");
        nodes.insert(url.clone(), NodeInfo {});
        let conn = pool.get().unwrap();
        let cs = clock_state.clone();
        thread::spawn(move || check_host(url.clone(), conn, cs));
    }
    return NodeList {
        nodes: nodes,
        pool: pool,
        clock: clock_state,
    };
}

fn get_nodes_list(req: &Request) -> Vec<String> {
    let state_ref = req.extensions.get::<State<Nodes>>().unwrap().read().unwrap();
    let nodelist = state_ref.deref();
    let mut vec = Vec::with_capacity(nodelist.nodes.len());
    for key in nodelist.nodes.keys() {
        vec.push(key.clone());
    }
    return vec;
}

fn insert_node(req: &mut Request, to_notify: &String) {
    let (conn, clock_state) = {
        let mut nodelist = req.extensions
            .get_mut::<State<Nodes>>()
            .unwrap()
            .write()
            .unwrap();
        let nodelist_dm = nodelist.deref_mut();
        nodelist_dm.nodes.insert(to_notify.clone(), NodeInfo {});
        (nodelist_dm.pool.get().unwrap(), nodelist_dm.clock.clone())
    };

    let url = to_notify.clone();
    thread::spawn(move || check_host(url, conn, clock_state));
}

pub fn notify_everyone(req: &Request, log_arc: Arc<Log>) {
    let nodes = get_nodes_list(req);
    for node in nodes {
        let local_log = log_arc.clone();
        thread::spawn(move || {
            let client = hyper::client::Client::new();
            let notify_url = format!("{}/log/other", node);
            debug!("Notifying (node) {}", notify_url);
            let res = client.post(&notify_url)
                .body(&serde_json::ser::to_string(&local_log).unwrap())
                .send();
            match res {
                Ok(val) => {
                    if val.status != hyper::status::StatusCode::Ok {
                        warn!("Failed to notify {:?}: {:?}", &node, val.status);
                    }
                }
                Err(val) => {
                    warn!("Failed to notify {:?}: {:?}", &node, val);
                }
            };
        });
    }
}

pub fn node_add(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering node {}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute("INSERT INTO nodes (url) VALUES ($1)", &[&url]) {
                Ok(_) => {
                    insert_node(req, &url);
                    Ok(Response::with((status::NoContent)))
                }
                Err(err) => {
                    if let postgres::error::Error::Db(dberr) = err {
                        match dberr.code {
                            SqlState::UniqueViolation => Ok(Response::with((status::NoContent))),
                            _ => Err(IronError::new(dberr, (status::BadRequest, "Some other error"))),
                        }
                    } else {
                        Err(IronError::new(err, (status::BadRequest, "Some other error")))
                    }
                }
            }
        }
    }
}

pub fn node_remove(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    conn.execute("DELETE from nodes where url = $1",
                 &[&url_from_body(req).unwrap().unwrap()])
        .expect("delete worked");
    Ok(Response::with((status::NoContent)))
}

pub fn node_list(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    let mut nodes = Vec::new();
    for row in &stmt.query(&[]).expect("last select works") {
        let url: String = row.get("url");
        nodes.push(url);
    }
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&nodes).unwrap())))
}
<commit_msg>Initial "node discovery" work<commit_after>use hyper;
use iron::prelude::{IronError, IronResult, Request, Response};
use iron::status;
use iron::typemap::Key;
use persistent;
use persistent::State;
use postgres;
use postgres::error::SqlState;
use potboiler_common::{db, url_from_body};
use potboiler_common::string_error::StringError;

use r2d2;
use r2d2_postgres;
use serde_json;
use serde_types::Log;
use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::iter::FromIterator;

use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use url::Url;
use uuid::Uuid;
pub type PostgresConnection = r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager>;
pub type PostgresPool = r2d2::Pool<r2d2_postgres::PostgresConnectionManager>;
use clock;
use hybrid_clocks::{Timestamp, WallT, Wall, Clock};
use std::sync::RwLock;
pub type SyncClock = Arc<RwLock<Clock<Wall>>>;

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

pub struct NodeInfo {
}

pub struct NodeList {
    nodes: HashMap<String, NodeInfo>,
    pool: PostgresPool,
    clock: SyncClock,
}

impl Key for Nodes {
    type Value = NodeList;
}

fn parse_json_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                           -> Result<serde_json::value::Value, StringError> {
    let mut res = match raw_result {
        Ok(val) => val,
        Err(val) => {
            return Err(StringError(format!("Failed to get logs: {:?}", val)));
        }
    };
    let body_string = {
        let mut body = String::new();
        res.read_to_string(&mut body).expect("could read from body");
        body
    };
    return match serde_json::de::from_str(&body_string) {
        Ok(val) => {
            debug!("Good data back {:?}", val);
            Ok(val)
        }
        Err(_) => Err(StringError(format!("Got crappy data back: {:?}", body_string))),
    };
}

fn parse_object_from_request(raw_result: Result<hyper::client::Response, hyper::Error>)
                             -> Result<serde_json::value::Map<String, serde_json::Value>, StringError> {
    let json: serde_json::Value = match parse_json_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => return Err(err),
    };
    return match json.as_object() {
        Some(val) => Ok(val.clone()),
        None => Err(StringError(format!("Info isn't a map: {:?}", json))),
    };
}

fn check_host_once(host_url: &String, conn: &PostgresConnection, clock_state: SyncClock) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/log", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let kv = match parse_object_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {:?}: {:?}", host_url, err);
            return;
        }
    };
    let stmt = conn.prepare("SELECT 1 from log where id=$1")
        .expect("prepare failure");
    for (key, value) in kv.iter() {
        let value_uuid = match Uuid::parse_str(value.as_str().unwrap()) {
            Ok(val) => val,
            Err(_) => {
                warn!("Value {} isn't a UUID!", value);
                continue;
            }
        };
        let key_uuid = match Uuid::parse_str(key) {
            Ok(val) => val,
            Err(_) => {
                warn!("Key {} isn't a UUID!", key);
                continue;
            }
        };
        let single_item = stmt.query(&[&value_uuid]).expect("bad single query");
        if !single_item.is_empty() {
            debug!("Already have {} locally", value_uuid);
            continue;
        }

        let first_item = conn.query("SELECT id from log WHERE prev is null and owner=$1 limit 1",
                   &[&key_uuid])
            .expect("bad first query");
        let start_uuid = if first_item.is_empty() {
            let first_url = format!("{}/log/first", &host_url);
            debug!("Get first from {:?}", host_url);
            let res = client.get(&first_url).send();
            let first_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("First entry: {:?}", first_entry);
            first_entry.get(key).unwrap().clone()
        } else {
            info!("Already have an entry from the list with server id {:?}",
                  key);
            let last_items = conn.query("SELECT id from log WHERE next is null and owner=$1 limit 1",
                       &[&key_uuid])
                .expect("bad last query");
            if last_items.is_empty() {
                warn!("Can't find end entry for server id {:?}", key);
                return;
            }
            let last_item = last_items.get(0);
            let last_item_id: Uuid = last_item.get("id");
            info!("Last item: {:?}", last_item_id);
            let last_url = format!("{}/log/{}", &host_url, last_item_id);
            debug!("Get last from {:?}", host_url);
            let res = client.get(&last_url).send();
            let last_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            info!("Last entry: {:?}", last_entry);
            last_entry.get("next").unwrap().clone()
        };
        let mut current_uuid = start_uuid;
        loop {
            let real_uuid = {
                let str_uuid = current_uuid.as_str();
                String::from(str_uuid.expect("UUID unwrap"))
            };
            let current_url = format!("{}/log/{}", &host_url, real_uuid);
            debug!("Get {} from {}", real_uuid, host_url);
            let res = client.get(&current_url).send();
            let current_entry = match parse_object_from_request(res) {
                Ok(val) => val,
                Err(err) => {
                    warn!("Error while getting first item from {:?}: {:?}",
                          host_url,
                          err);
                    return;
                }
            };
            let next = current_entry.get("next").expect("has next key");
            let timestamp: Timestamp<WallT> =
                serde_json::value::from_value(current_entry.get("when").expect(" has when key").clone())
                    .expect("is byte string");
            clock::observe_timestamp(&clock_state, timestamp);
            let log = Log {
                id: Uuid::parse_str(&real_uuid).unwrap(),
                owner: key_uuid,
                next: get_uuid_from_map(&current_entry, "next"),
                prev: get_uuid_from_map(&current_entry, "prev"),
                data: current_entry.get("data").unwrap().clone(),
                when: clock::get_timestamp_from_state(&clock_state),
            };
            insert_log(conn, &log);
            if next.is_null() {
                break;
            }
            current_uuid = next.clone();
        }
    }
}

fn get_uuid_from_map(map: &serde_json::value::Map<String, serde_json::Value>, key: &str) -> Option<Uuid> {
    let value = map.get(key).unwrap();
    if value.is_null() {
        None
    } else {
        Some(Uuid::parse_str(value.as_str().unwrap()).unwrap())
    }
}

pub fn insert_log(conn: &PostgresConnection, log: &Log) {
    debug!("Inserting {:?}", log);
    if log.prev.is_some() {
        conn.execute("UPDATE log set next = $1 where owner = $2 and id = $3",
                     &[&log.id, &log.owner, &log.prev])
            .expect("update worked");
    }
    let raw_timestamp = clock::get_raw_timestamp(&log.when);
    conn.execute("INSERT INTO log (id, owner, data, prev, hlc_tstamp) VALUES ($1, $2, $3, $4, $5)",
                 &[&log.id, &log.owner, &log.data, &log.prev, &raw_timestamp])
        .expect("insert worked");
}

fn check_new_nodes(host_url: &String, conn: &PostgresConnection) {
    let client = hyper::client::Client::new();
    let check_url = format!("{}/nodes", &host_url);
    info!("Checking {} ({})", host_url, check_url);
    let raw_result = client.get(&check_url).send();
    let nodes = match parse_json_from_request(raw_result) {
        Ok(val) => val,
        Err(err) => {
            warn!("Error while getting from {:?}: {:?}", host_url, err);
            return;
        }
    };
    let new_nodes: HashSet<String> =
        HashSet::from_iter(nodes.as_array().unwrap().iter().map(|x| String::from(x.as_str().unwrap())));
    let existing_nodes = conn.query("SELECT url from nodes", &[])
        .expect("prepare failure");
    let existing_nodes_set: HashSet<String> = HashSet::from_iter(existing_nodes.iter()
        .map(|x| x.get::<&str, String>("url")));
    let extra_nodes = new_nodes.difference(&existing_nodes_set).collect::<Vec<&String>>();
    info!("existing_nodes: {:?} {:?} {:?}",
          existing_nodes_set,
          new_nodes,
          extra_nodes);
}

fn check_host(host_url: String, conn: PostgresConnection, clock_state: SyncClock) {
    let sleep_time = Duration::from_secs(5);
    loop {
        check_host_once(&host_url, &conn, clock_state.clone());
        check_new_nodes(&host_url, &conn);
        thread::sleep(sleep_time);
    }
}

pub fn initial_nodes(pool: PostgresPool, clock_state: SyncClock) -> NodeList {
    let conn = pool.get().unwrap();
    let mut nodes = HashMap::new();
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    for row in &stmt.query(&[]).expect("nodes select works") {
        let url: String = row.get("url");
        nodes.insert(url.clone(), NodeInfo {});
        let conn = pool.get().unwrap();
        let cs = clock_state.clone();
        thread::spawn(move || check_host(url.clone(), conn, cs));
    }
    return NodeList {
        nodes: nodes,
        pool: pool,
        clock: clock_state,
    };
}

fn get_nodes_list(req: &Request) -> Vec<String> {
    let state_ref = req.extensions.get::<State<Nodes>>().unwrap().read().unwrap();
    let nodelist = state_ref.deref();
    let mut vec = Vec::with_capacity(nodelist.nodes.len());
    for key in nodelist.nodes.keys() {
        vec.push(key.clone());
    }
    return vec;
}

fn insert_node(req: &mut Request, to_notify: &String) {
    let (conn, clock_state) = {
        let mut nodelist = req.extensions
            .get_mut::<State<Nodes>>()
            .unwrap()
            .write()
            .unwrap();
        let nodelist_dm = nodelist.deref_mut();
        nodelist_dm.nodes.insert(to_notify.clone(), NodeInfo {});
        (nodelist_dm.pool.get().unwrap(), nodelist_dm.clock.clone())
    };

    let url = to_notify.clone();
    thread::spawn(move || check_host(url, conn, clock_state));
}

pub fn notify_everyone(req: &Request, log_arc: Arc<Log>) {
    let nodes = get_nodes_list(req);
    for node in nodes {
        let local_log = log_arc.clone();
        thread::spawn(move || {
            let client = hyper::client::Client::new();
            let notify_url = format!("{}/log/other", node);
            debug!("Notifying (node) {}", notify_url);
            let res = client.post(&notify_url)
                .body(&serde_json::ser::to_string(&local_log).unwrap())
                .send();
            match res {
                Ok(val) => {
                    if val.status != hyper::status::StatusCode::Ok {
                        warn!("Failed to notify {:?}: {:?}", &node, val.status);
                    }
                }
                Err(val) => {
                    warn!("Failed to notify {:?}: {:?}", &node, val);
                }
            };
        });
    }
}

pub fn node_add(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering node {}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute("INSERT INTO nodes (url) VALUES ($1)", &[&url]) {
                Ok(_) => {
                    insert_node(req, &url);
                    Ok(Response::with((status::NoContent)))
                }
                Err(err) => {
                    if let postgres::error::Error::Db(dberr) = err {
                        match dberr.code {
                            SqlState::UniqueViolation => Ok(Response::with((status::NoContent))),
                            _ => Err(IronError::new(dberr, (status::BadRequest, "Some other error"))),
                        }
                    } else {
                        Err(IronError::new(err, (status::BadRequest, "Some other error")))
                    }
                }
            }
        }
    }
}

pub fn node_remove(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    conn.execute("DELETE from nodes where url = $1",
                 &[&url_from_body(req).unwrap().unwrap()])
        .expect("delete worked");
    Ok(Response::with((status::NoContent)))
}

pub fn node_list(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("select url from nodes").expect("prepare failure");
    let mut nodes = Vec::new();
    for row in &stmt.query(&[]).expect("last select works") {
        let url: String = row.get("url");
        nodes.push(url);
    }
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&nodes).unwrap())))
}
<|endoftext|>


<commit_before>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	BIF(~str, int, ~[~str], extern fn(@mut HashMap<~str, ~LispValue>, ~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _, _), BIF(ref y, _, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Returns a value representing the empty list
#[inline]
pub fn nil() -> ~LispValue {
	~List(~[])
}

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: @mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: @mut SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Identity function
fn id_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue { v[0] }

fn cons_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v {
		[~a, ~b, .._] => ~List(~[a, b]),
		_ => fail!("cons: requires two arguments")
	}
}

fn car_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[0],
		_ => fail!("car: need a list")
	}
}

fn cdr_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[1],
		_ => fail!("cdr: need a list")
	}
}

// Print function
fn print_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~Str(s) => printfln!("%s", s),
		_ => fail!("print takes an str")
	}
	nil()
}

// There are several bugs in the macroing system (#8853, or, #8852 and #8851)
// that prevent us from making these functions macros. In addition, we can't
// return a closure because the type needs to be `extern "Rust" fn`, which
// closures aren't. So we have a little bit of code duplication.

fn plus_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("+ needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let add = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() + y.clone()),
			(Str(ref x), &~Str(ref y)) => ~Str(x.clone() + y.clone()),
			_ => fail!("invalid operands to +")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), add)
}

fn minus_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("- needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let sub = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() - y.clone()),
			_ => fail!("invalid operands to -")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), sub)
}

fn mul_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("* needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let mul = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() * y.clone()),
			_ => fail!("invalid operands to *")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), mul)
}

fn div_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("/ needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let div = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() / y.clone()),
			_ => fail!("invalid operands to /")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), div)
}

/// Initializes standard library functions
pub fn init_std(symt: @mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", 1, ~[~"x"], id_));
	bind(symt, ~"print", ~BIF(~"print", 1, ~[~"msg"], print_));
	bind(symt, ~"cons", ~BIF(~"cons", 2, ~[~"x", ~"y"], cons_));
	bind(symt, ~"car", ~BIF(~"car", 1, ~[~"x"], car_));
	bind(symt, ~"cdr", ~BIF(~"cdr", 1, ~[~"x"], cdr_));
	bind(symt, ~"+", ~BIF(~"+", -1, ~[], plus_));
	bind(symt, ~"*", ~BIF(~"*", -1, ~[], mul_));
	bind(symt, ~"-", ~BIF(~"-", -1, ~[], minus_));
	bind(symt, ~"/", ~BIF(~"/", -1, ~[], div_));
}

fn apply(symt: @mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	match *f {
		BIF(name, arity, fnargs, bif) => {
			// apply built-in function
			if arity > 0 && fnargs.len() as int != arity {
				fail!("function '%s' requires %d arguments, but it received %u arguments",
					name, arity, args.len())
			}

			bif(symt, args)
		}

		_ => fail!("apply: need function")
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: @mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// evaluate a list as a function call
			match v {
				[sexpr::Atom(sym), ..args] => {
					let f = lookup(symt, sym);
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

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

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("123")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id 123)")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id (id (id 123)))")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_str() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(id \"hi\")")), ~Str(~"hi"));
		assert_eq!(eval(symt, read("(car (cons \"a\" \"b\"))")), ~Str(~"a"));
	}

	#[test]
	fn test_cons() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cons 1 2)")), ~List(~[Num(1.0), Num(2.0)]));
		assert_eq!(eval(symt, read("(cons 1 (cons 2 3))")), ~List(~[Num(1.0),
			List(~[Num(2.0), Num(3.0)])]));
	}

	#[test]
	fn test_car() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(car (cons 1 2))")), ~Num(1.0));
	}

	#[test]
	fn test_cdr() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cdr (cons 1 2))")), ~Num(2.0));
		assert_eq!(eval(symt, read("(cdr (cons 1 (cons 2 3)))")), ~List(~[Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_arithmetic() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(+ 1 3)")), ~Num(4.0));
		assert_eq!(eval(symt, read("(+ 1.5 3)")), ~Num(4.5));
		assert_eq!(eval(symt, read("(+ 5 -3)")), ~Num(2.0));

		assert_eq!(eval(symt, read("(- 5 3)")), ~Num(2.0));
		assert_eq!(eval(symt, read("(- 3 5)")), ~Num(-2.0));
		assert_eq!(eval(symt, read("(- 5 -3)")), ~Num(8.0));

		assert_eq!(eval(symt, read("(* 2 5)")), ~Num(10.0));
		assert_eq!(eval(symt, read("(* 2 -5)")), ~Num(-10.0));

		assert_eq!(eval(symt, read("(/ 10 2)")), ~Num(5.0));
		assert_eq!(eval(symt, read("(/ 10 -2)")), ~Num(-5.0));
	}
}<commit_msg>Add quote special form<commit_after>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	BIF(~str, int, ~[~str], extern fn(@mut HashMap<~str, ~LispValue>, ~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _, _), BIF(ref y, _, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Returns a value representing the empty list
#[inline]
pub fn nil() -> ~LispValue {
	~List(~[])
}

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: @mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: @mut SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Identity function
fn id_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue { v[0] }

fn cons_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v {
		[~a, ~b, .._] => ~List(~[a, b]),
		_ => fail!("cons: requires two arguments")
	}
}

fn car_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[0],
		_ => fail!("car: need a list")
	}
}

fn cdr_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~List(v_) => ~v_[1],
		_ => fail!("cdr: need a list")
	}
}

// Print function
fn print_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	match v[0] {
		~Str(s) => printfln!("%s", s),
		_ => fail!("print takes an str")
	}
	nil()
}

// There are several bugs in the macroing system (#8853, or, #8852 and #8851)
// that prevent us from making these functions macros. In addition, we can't
// return a closure because the type needs to be `extern "Rust" fn`, which
// closures aren't. So we have a little bit of code duplication.

fn plus_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("+ needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let add = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() + y.clone()),
			(Str(ref x), &~Str(ref y)) => ~Str(x.clone() + y.clone()),
			_ => fail!("invalid operands to +")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), add)
}

fn minus_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("- needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let sub = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() - y.clone()),
			_ => fail!("invalid operands to -")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), sub)
}

fn mul_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("* needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let mul = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() * y.clone()),
			_ => fail!("invalid operands to *")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), mul)
}

fn div_(_symt: @mut SymbolTable, v: ~[~LispValue]) -> ~LispValue {
	if(v.len() == 0) { fail!("/ needs operands"); }
	else if(v.len() == 1) {
		return v[0];
	}

	let div = |acc: ~LispValue, b: &~LispValue| {
		match (*acc, b) {
			(Num(ref x), &~Num(ref y)) => ~Num(x.clone() / y.clone()),
			_ => fail!("invalid operands to /")
		}
	};

	v.iter().skip(1).fold(v[0].clone(), div)
}

/// Initializes standard library functions
pub fn init_std(symt: @mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", 1, ~[~"x"], id_));
	bind(symt, ~"print", ~BIF(~"print", 1, ~[~"msg"], print_));
	bind(symt, ~"cons", ~BIF(~"cons", 2, ~[~"x", ~"y"], cons_));
	bind(symt, ~"car", ~BIF(~"car", 1, ~[~"x"], car_));
	bind(symt, ~"cdr", ~BIF(~"cdr", 1, ~[~"x"], cdr_));
	bind(symt, ~"+", ~BIF(~"+", -1, ~[], plus_));
	bind(symt, ~"*", ~BIF(~"*", -1, ~[], mul_));
	bind(symt, ~"-", ~BIF(~"-", -1, ~[], minus_));
	bind(symt, ~"/", ~BIF(~"/", -1, ~[], div_));
}

fn apply(symt: @mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	match *f {
		BIF(name, arity, fnargs, bif) => {
			// apply built-in function
			if arity > 0 && fnargs.len() as int != arity {
				fail!("function '%s' requires %d arguments, but it received %u arguments",
					name, arity, args.len())
			}

			bif(symt, args)
		}

		_ => fail!("apply: need function")
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: @mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// evaluate a list as a function call
			match v {
				[sexpr::Atom(~"quote"), arg] => from_sexpr(&arg),
				[sexpr::Atom(sym), ..args] => {
					let f = lookup(symt, sym);
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

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

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("123")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id 123)")), ~Num(123.0));
		assert_eq!(eval(symt, read("(id (id (id 123)))")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_str() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(id \"hi\")")), ~Str(~"hi"));
		assert_eq!(eval(symt, read("(car (cons \"a\" \"b\"))")), ~Str(~"a"));
	}

	#[test]
	fn test_cons() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cons 1 2)")), ~List(~[Num(1.0), Num(2.0)]));
		assert_eq!(eval(symt, read("(cons 1 (cons 2 3))")), ~List(~[Num(1.0),
			List(~[Num(2.0), Num(3.0)])]));
	}

	#[test]
	fn test_car() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(car (cons 1 2))")), ~Num(1.0));
	}

	#[test]
	fn test_cdr() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(cdr (cons 1 2))")), ~Num(2.0));
		assert_eq!(eval(symt, read("(cdr (cons 1 (cons 2 3)))")), ~List(~[Num(2.0), Num(3.0)]));
	}

	#[test]
	fn test_arithmetic() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(+ 1 3)")), ~Num(4.0));
		assert_eq!(eval(symt, read("(+ 1.5 3)")), ~Num(4.5));
		assert_eq!(eval(symt, read("(+ 5 -3)")), ~Num(2.0));

		assert_eq!(eval(symt, read("(- 5 3)")), ~Num(2.0));
		assert_eq!(eval(symt, read("(- 3 5)")), ~Num(-2.0));
		assert_eq!(eval(symt, read("(- 5 -3)")), ~Num(8.0));

		assert_eq!(eval(symt, read("(* 2 5)")), ~Num(10.0));
		assert_eq!(eval(symt, read("(* 2 -5)")), ~Num(-10.0));

		assert_eq!(eval(symt, read("(/ 10 2)")), ~Num(5.0));
		assert_eq!(eval(symt, read("(/ 10 -2)")), ~Num(-5.0));
	}

	#[test]
	fn test_quote() {
		let symt = @mut new_symt();
		init_std(symt);
		assert_eq!(eval(symt, read("(quote 5)")), ~Num(5.0));
		assert_eq!(eval(symt, read("(quote x)")), ~Atom(~"x"));
		assert_eq!(eval(symt, read("(quote (1 2 3))")), ~List(~[Num(1f), Num(2f), Num(3f)]));
	}
}<|endoftext|>


<commit_before>use std::cmp;
use std::env;
use std::fs;

fn main() {
    let uid = unsafe { geteuid() };
    if uid != 0 {
        panic!("UID {} is not root", uid);
    }

    let args: Vec<String> = env::args().collect();
    match args.as_slice() {
        [_, x] => run(x),
        _ => help(),
    }
}

fn run(cmd: &str) {
    match cmd {
        "+" => set(percent() + 10),
        "-" => set(percent() - 10),
        n if n.parse::<i64>().is_ok() => set(n.parse::<i64>().unwrap()),
        _ => help(),
    }
}

fn help() {
    println!("brightness +|-|N");
}

fn max() -> i64 {
    read("/sys/class/backlight/intel_backlight/max_brightness")
}

fn current() -> i64 {
    read("/sys/class/backlight/intel_backlight/brightness")
}

fn percent() -> i64 {
    (100 * current()) / max()
}

fn set(p: i64) {
    let p = cmp::max(5, cmp::min(100, p));
    println!("Set to {}%", p);
    write(p * max() / 100)
}

fn read(path: &str) -> i64 {
    fs::read_to_string(path)
        .unwrap_or_else(|_| panic!("Couldn't open file: {}", path))
        .trim()
        .parse::<i64>()
        .unwrap_or_else(|e| panic!("Failed to read number from `{}`", e))
}

fn write(b: i64) {
    fs::write(
        "/sys/class/backlight/intel_backlight/brightness",
        b.to_string(),
    )
    .unwrap();
}

#[link(name = "c")]
extern "C" {
    fn geteuid() -> u32;
// fn getegid() -> u32;
}

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

    #[test]
    fn t_test() {
        assert_eq!(7500, max());
        assert!(current() <= 7500);
        assert!(percent() < 100);
    }

    #[test]
    #[ignore]
    fn t_write() {
        write(5000)
    }
}
<commit_msg>Tiny tweaks to brightness controller<commit_after>#![feature(clamp)]
use std::{env, fs};

fn main() {
    let uid = unsafe { geteuid() };
    if uid != 0 {
        panic!("UID {} is not root", uid);
    }

    let args: Vec<String> = env::args().collect();
    match args.as_slice() {
        [_, x] => run(x),
        _ => help(),
    }
}

fn run(cmd: &str) {
    match cmd {
        "+" => set(percent() + 10),
        "-" => set(percent() - 10),
        n if n.parse::<i64>().is_ok() => set(n.parse::<i64>().unwrap()),
        _ => help(),
    }
}

fn help() {
    println!("brightness +|-|N");
}

fn max() -> i64 {
    read("/sys/class/backlight/intel_backlight/max_brightness")
}

fn current() -> i64 {
    read("/sys/class/backlight/intel_backlight/brightness")
}

fn percent() -> i64 {
    (100 * current()) / max()
}

fn set(p: i64) {
    let p = p.clamp(5, 100);
    write(p * max() / 100)
}

fn read(path: &str) -> i64 {
    fs::read_to_string(path)
        .unwrap_or_else(|_| panic!("Couldn't open file: {}", path))
        .trim()
        .parse::<i64>()
        .unwrap_or_else(|e| panic!("Failed to read number from `{}`", e))
}

fn write(b: i64) {
    fs::write(
        "/sys/class/backlight/intel_backlight/brightness",
        b.to_string(),
    )
    .unwrap();
}

#[link(name = "c")]
extern "C" {
    fn geteuid() -> u32;
}

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

    #[test]
    fn t_test() {
        assert_eq!(7500, max());
        assert!(current() <= 7500);
        assert!(percent() < 100);
    }

    #[test]
    #[ignore]
    fn t_write() {
        write(5000)
    }
}
<|endoftext|>


<commit_before><commit_msg>(test) Tested Persistent.<commit_after>extern crate iron;
extern crate persistent;

#[cfg(test)]
mod test {
    use std::sync::{Arc, Mutex};
    use persistent::Persistent;
    use iron::{Chain, StackChain, Request, Response, Alloy};
    use std::mem::uninitialized;

    fn unsafe_dispatch<C: Chain>(chain: &mut C) {
        unsafe {
            let _ = chain.dispatch(uninitialized(), uninitialized(), None);
        }
    }

    #[test]
    fn inserts_data() {
        fn data_exists(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
            assert_eq!(*alloy.find::<Persistent<int, int>>().unwrap().data.lock(), 154);
        }

        let data = Arc::new(Mutex::new(154));
        let persistent: Persistent<int, int> = Persistent { data: data.clone() };
        let mut testchain: StackChain = Chain::new();
        testchain.link(persistent);
        testchain.link(data_exists);

        unsafe_dispatch(&mut testchain);
    }

    #[test]
    fn changes_when_modified() {
        fn modify_data(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
            *alloy.find::<Persistent<int, int>>().unwrap().data.lock() += 1;
        }

        fn data_modified(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
            assert_eq!(*alloy.find::<Persistent<int, int>>().unwrap().data.lock(), 155);
        }

        let data = Arc::new(Mutex::new(154));
        let persistent: Persistent<int, int> = Persistent { data: data.clone() };
        let mut testchain: StackChain = Chain::new();
        testchain.link(persistent);
        testchain.link(modify_data);
        testchain.link(data_modified);

        unsafe_dispatch(&mut testchain);
    }

    #[test]
    fn persists_between_calls() {
        fn modify_data(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
            *alloy.find::<Persistent<int, int>>().unwrap().data.lock() += 1;
        }

        fn data_modified(_: &mut Request, _: &mut Response, alloy: &mut Alloy) {
            assert_eq!(*alloy.find::<Persistent<int, int>>().unwrap().data.lock(), 156);
        }

        let data = Arc::new(Mutex::new(154));
        let persistent: Persistent<int, int> = Persistent { data: data.clone() };
        let mut testchain: StackChain = Chain::new();
        testchain.link(persistent);
        testchain.link(modify_data);
        unsafe_dispatch(&mut testchain);

        testchain.link(data_modified);
        unsafe_dispatch(&mut testchain);
    }
}

<|endoftext|>