<commit_before>use std::mem;
use std::sync::Arc;
use base64::{encode_mode, decode_mode, Base64Error, Base64Mode};
use byteorder::{ByteOrder, BigEndian};

use ::crypto::{Hash, hash, HASH_SIZE};
use ::messages::{MessageBuffer, Message, AnyTx};

#[derive(Clone)]
pub struct HeightBytes(pub [u8; 32]);

pub trait StorageValue {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8>;
    ///to inform caller what capacity is needed for serialize beforehand
    fn len_hint(&self) -> usize {
        0
    }
    fn deserialize(v: Vec<u8>) -> Self;
    fn hash(&self) -> Hash {
        hash(&self.serialize(Vec::new()))
    }
}

pub fn repr_stor_val<T: StorageValue>(value: &T) -> String {
    let vec_bytes = value.serialize(Vec::new());
    encode_mode(&vec_bytes, Base64Mode::UrlSafe)
}

pub fn decode_from_b64_string<T: StorageValue>(b64: &str) -> Result<T, Base64Error> {
    let vec_bytes = decode_mode(b64, Base64Mode::UrlSafe)?;
    Ok(StorageValue::deserialize(vec_bytes))
}

impl StorageValue for u16 {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<u16>();
        buf.resize(new_len, 0);

        BigEndian::write_u16(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_u16(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<u16>()
    }
}

impl StorageValue for u32 {
    // TODO: return Cow<[u8]>
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<u32>();
        buf.resize(new_len, 0);
        BigEndian::write_u32(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_u32(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<u32>()
    }
}

impl StorageValue for u64 {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<u64>();
        buf.resize(new_len, 0);
        BigEndian::write_u64(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_u64(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<u64>()
    }
}

impl StorageValue for i64 {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<i64>();
        buf.resize(new_len, 0);
        BigEndian::write_i64(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_i64(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<i64>()
    }
}

impl StorageValue for Hash {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {

        let byteslice = self.as_ref();
        let old_len = buf.len();
        let new_len = old_len + byteslice.len();
        buf.resize(new_len, 0);
        {
            let part = &mut buf[old_len..new_len];
            part.copy_from_slice(byteslice);
        }
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        Hash::from_slice(&v).unwrap()
    }

    fn len_hint(&self) -> usize {
        HASH_SIZE
    }

    fn hash(&self) -> Hash {
        *self
    }
}

// impl StorageValue for RawMessage {
//     fn serialize(self) -> Vec<u8> {
//         self.as_ref().as_ref().to_vec()
//     }

//     fn deserialize(v: Vec<u8>) -> Self {
//         Arc::new(MessageBuffer::from_vec(v))
//     }

//     fn hash(&self) -> Hash {
//         self.as_ref().hash()
//     }
// }

impl<T> StorageValue for T
    where T: Message
{
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let byteslice = self.raw().as_ref().as_ref();
        let old_len = buf.len();
        let new_len = old_len + byteslice.len();
        buf.resize(new_len, 0);
        {
            let part = &mut buf[old_len..new_len];
            part.copy_from_slice(byteslice);
        }
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        Message::from_raw(Arc::new(MessageBuffer::from_vec(v))).unwrap()
    }

    fn len_hint(&self) -> usize {
        self.raw().as_ref().as_ref().len()
    }

    fn hash(&self) -> Hash {
        <Self as Message>::hash(self)
    }
}

impl<AppTx> StorageValue for AnyTx<AppTx>
    where AppTx: Message
{
    fn serialize(self) -> Vec<u8> {
        self.raw().as_ref().as_ref().to_vec()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        let raw = Arc::new(MessageBuffer::from_vec(v));
        Self::from_raw(raw).unwrap()
    }

    fn hash(&self) -> Hash {
        self.hash()
    }
}

impl StorageValue for Vec<u8> {

    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + self.len();
        buf.resize(new_len, 0);
        {
            let part = &mut buf[old_len..new_len];
            part.copy_from_slice(self);
        }
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        v
    }

    fn len_hint(&self) -> usize {
        self.len()
    }
    fn hash(&self) -> Hash {
        hash(self)
    }
}

impl AsRef<[u8]> for HeightBytes {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl From<u64> for HeightBytes {
    fn from(b: u64) -> HeightBytes {
        let mut v = [0u8; 32];
        BigEndian::write_u64(&mut v, b);
        HeightBytes(v)
    }
}

impl From<HeightBytes> for u64 {
    fn from(b: HeightBytes) -> u64 {
        BigEndian::read_u64(b.as_ref())
    }
}

impl StorageValue for HeightBytes {
    fn serialize(self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        let mut b = [0u8; 32];
        b.clone_from_slice(v.as_slice());
        HeightBytes(b)
    }

    fn hash(&self) -> Hash {
        hash(self.as_ref())
    }
}
<commit_msg>Removed latest nightly warning: "patterns aren't allowed in methods without bodies".<commit_after>use std::mem;
use std::sync::Arc;
use base64::{encode_mode, decode_mode, Base64Error, Base64Mode};
use byteorder::{ByteOrder, BigEndian};

use ::crypto::{Hash, hash, HASH_SIZE};
use ::messages::{MessageBuffer, Message, AnyTx};

#[derive(Clone)]
pub struct HeightBytes(pub [u8; 32]);

pub trait StorageValue {
    fn serialize(&self, buf: Vec<u8>) -> Vec<u8>;
    ///to inform caller what capacity is needed for serialize beforehand
    fn len_hint(&self) -> usize {
        0
    }
    fn deserialize(v: Vec<u8>) -> Self;
    fn hash(&self) -> Hash {
        hash(&self.serialize(Vec::new()))
    }
}

pub fn repr_stor_val<T: StorageValue>(value: &T) -> String {
    let vec_bytes = value.serialize(Vec::new());
    encode_mode(&vec_bytes, Base64Mode::UrlSafe)
}

pub fn decode_from_b64_string<T: StorageValue>(b64: &str) -> Result<T, Base64Error> {
    let vec_bytes = decode_mode(b64, Base64Mode::UrlSafe)?;
    Ok(StorageValue::deserialize(vec_bytes))
}

impl StorageValue for u16 {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<u16>();
        buf.resize(new_len, 0);

        BigEndian::write_u16(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_u16(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<u16>()
    }
}

impl StorageValue for u32 {
    // TODO: return Cow<[u8]>
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<u32>();
        buf.resize(new_len, 0);
        BigEndian::write_u32(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_u32(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<u32>()
    }
}

impl StorageValue for u64 {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<u64>();
        buf.resize(new_len, 0);
        BigEndian::write_u64(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_u64(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<u64>()
    }
}

impl StorageValue for i64 {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + mem::size_of::<i64>();
        buf.resize(new_len, 0);
        BigEndian::write_i64(&mut buf[old_len..new_len], *self);
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        BigEndian::read_i64(&v)
    }

    fn len_hint(&self) -> usize {
        mem::size_of::<i64>()
    }
}

impl StorageValue for Hash {
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {

        let byteslice = self.as_ref();
        let old_len = buf.len();
        let new_len = old_len + byteslice.len();
        buf.resize(new_len, 0);
        {
            let part = &mut buf[old_len..new_len];
            part.copy_from_slice(byteslice);
        }
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        Hash::from_slice(&v).unwrap()
    }

    fn len_hint(&self) -> usize {
        HASH_SIZE
    }

    fn hash(&self) -> Hash {
        *self
    }
}

// impl StorageValue for RawMessage {
//     fn serialize(self) -> Vec<u8> {
//         self.as_ref().as_ref().to_vec()
//     }

//     fn deserialize(v: Vec<u8>) -> Self {
//         Arc::new(MessageBuffer::from_vec(v))
//     }

//     fn hash(&self) -> Hash {
//         self.as_ref().hash()
//     }
// }

impl<T> StorageValue for T
    where T: Message
{
    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let byteslice = self.raw().as_ref().as_ref();
        let old_len = buf.len();
        let new_len = old_len + byteslice.len();
        buf.resize(new_len, 0);
        {
            let part = &mut buf[old_len..new_len];
            part.copy_from_slice(byteslice);
        }
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        Message::from_raw(Arc::new(MessageBuffer::from_vec(v))).unwrap()
    }

    fn len_hint(&self) -> usize {
        self.raw().as_ref().as_ref().len()
    }

    fn hash(&self) -> Hash {
        <Self as Message>::hash(self)
    }
}

impl<AppTx> StorageValue for AnyTx<AppTx>
    where AppTx: Message
{
    fn serialize(self) -> Vec<u8> {
        self.raw().as_ref().as_ref().to_vec()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        let raw = Arc::new(MessageBuffer::from_vec(v));
        Self::from_raw(raw).unwrap()
    }

    fn hash(&self) -> Hash {
        self.hash()
    }
}

impl StorageValue for Vec<u8> {

    fn serialize(&self, mut buf: Vec<u8>) -> Vec<u8> {
        let old_len = buf.len();
        let new_len = old_len + self.len();
        buf.resize(new_len, 0);
        {
            let part = &mut buf[old_len..new_len];
            part.copy_from_slice(self);
        }
        buf
    }

    fn deserialize(v: Vec<u8>) -> Self {
        v
    }

    fn len_hint(&self) -> usize {
        self.len()
    }
    fn hash(&self) -> Hash {
        hash(self)
    }
}

impl AsRef<[u8]> for HeightBytes {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl From<u64> for HeightBytes {
    fn from(b: u64) -> HeightBytes {
        let mut v = [0u8; 32];
        BigEndian::write_u64(&mut v, b);
        HeightBytes(v)
    }
}

impl From<HeightBytes> for u64 {
    fn from(b: HeightBytes) -> u64 {
        BigEndian::read_u64(b.as_ref())
    }
}

impl StorageValue for HeightBytes {
    fn serialize(self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        let mut b = [0u8; 32];
        b.clone_from_slice(v.as_slice());
        HeightBytes(b)
    }

    fn hash(&self) -> Hash {
        hash(self.as_ref())
    }
}
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use std::io::IoResult;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        let pred = |&:line: &IoResult<String>| {
            if let Ok(ref l) = *line {
                l.starts_with(short_name)
            } else {
                true
            }
        };
        match line_iter.find(pred) {
            Some(Ok(ref line)) => decode_line(line),
            Some(Err(_)) => Err(DatabaseError(CTDatabaseError {
                desc: "Error reading the database".to_string()
            })),
            None => Err(SyntaxError(CTSyntaxError {
                desc: format!("Could not find element: {:?}", short_name),
                pos: elem.pos,
                len: elem.len,
            })),
        }
    }

    pub fn get_data(&mut self, elems: &Vec<Token>) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
           match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use token::Token;
    use token::TokenKind::Elem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4");
        let raw_result = db.get_data(&vec!(
            Token { tok: Elem("B".to_string()), pos: 0, len: 1 },
            Token { tok: Elem("A".to_string()), pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0");
        let raw_result = db.get_single_data(&Token { tok: Elem("B".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("B".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn decode() {
        let db_name = "decode_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let raw_result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "A".to_string(),
            long_name: "Abba".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<commit_msg>Rename search predicate to make target more clear<commit_after>use std::io::{File, BufferedReader};
use std::io::SeekStyle::SeekSet;
use std::io::IoResult;
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_single_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        // we return to the beginning of the underlying file, since the data
        // might lie on a line we have previously read past
        self.db.get_mut().seek(0, SeekSet).ok().expect("Internal error reading database");
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        let elem_or_err = |&:line: &IoResult<String>| {
            if let Ok(ref l) = *line {
                l.starts_with(short_name)
            } else {
                true
            }
        };
        match line_iter.find(elem_or_err) {
            Some(Ok(ref line)) => decode_line(line),
            Some(Err(_)) => Err(DatabaseError(CTDatabaseError {
                desc: "Error reading the database".to_string()
            })),
            None => Err(SyntaxError(CTSyntaxError {
                desc: format!("Could not find element: {:?}", short_name),
                pos: elem.pos,
                len: elem.len,
            })),
        }
    }

    pub fn get_data(&mut self, elems: &Vec<Token>) -> CTResult<Vec<ElemData>> {
        let mut out = Vec::new();
        for elem in elems.iter() {
           match self.get_single_data(elem) {
                Ok(data) => out.push(data),
                Err(e) => return Err(e),
            }
        }
        Ok(out)
    }
}

fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::File;
    use std::io::fs;
    use token::Token;
    use token::TokenKind::Elem;

    fn make_dummy_db(name: &str, contents: &str) -> ElemDatabase {
        if let Err(e) = File::create(&Path::new(name)).and_then(|mut f| f.write_str(contents)) {
            // if we can't make the database we can't test, so just abort here
            panic!("Could not create dummy database: {:?}", e.desc);
        }
        ElemDatabase::open(name).unwrap()
    }

    fn remove_dummy_db(name: &str) {
        if let Err(e) = fs::unlink(&Path::new(name)) {
            // if we can't remove the database something is wrong, and we abort the test
            panic!("Could not remove dummy database: {:?}", e.desc);
        }
    }

    #[test]
    fn multiple_elems() {
        let db_name = "multiple_elems_db";
        let mut db = make_dummy_db(db_name,
            "A;1;Abba;2\n\
            B;3;Beta;4");
        let raw_result = db.get_data(&vec!(
            Token { tok: Elem("B".to_string()), pos: 0, len: 1 },
            Token { tok: Elem("A".to_string()), pos: 1, len: 1 }
        ));
        let expected = vec!(
            ElemData {
                short_name: "B".to_string(),
                long_name: "Beta".to_string(),
                mass: 3.0,
                atomic_num: 4,
            },
            ElemData {
                short_name: "A".to_string(),
                long_name: "Abba".to_string(),
                mass: 1.0,
                atomic_num: 2,
            }
        );
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn find_elem() {
        let db_name = "find_elem_db";
        let mut db = make_dummy_db(db_name,
            "A;0;Abba;0\n\
            B;123.456789;Beta;12\n\
            C;0;Coop;0");
        let raw_result = db.get_single_data(&Token { tok: Elem("B".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "B".to_string(),
            long_name: "Beta".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_elem() {
        let db_name = "missing_elem_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("B".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn decode() {
        let db_name = "decode_db";
        let mut db = make_dummy_db(db_name, "A;123.456789;Abba;12");
        let raw_result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        let expected = ElemData {
            short_name: "A".to_string(),
            long_name: "Abba".to_string(),
            mass: 123.456789,
            atomic_num: 12,
        };
        remove_dummy_db(db_name);
        assert_eq!(Ok(expected), raw_result);
    }

    #[test]
    fn missing_field() {
        let db_name = "missing_field_db";
        let mut db = make_dummy_db(db_name, "A;");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }

    #[test]
    fn field_corrupted() {
        let db_name = "field_corrupted_db";
        let mut db = make_dummy_db(db_name, "A;not a number;Abba;12");
        let result = db.get_single_data(&Token { tok: Elem("A".to_string()), pos: 0, len: 2 });
        remove_dummy_db(db_name);
        assert!(result.is_err());
    }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::fs;
use std::env;
use std::os::unix::fs::PermissionsExt;
use std::io::{Write,BufReader};
use std::io::BufRead;
use std::process::Command;
use std::path::Path;

const SNAPPY_VERSION: &'static str  = "1.1.2";
const LEVELDB_VERSION: &'static str = "1.18";

fn build_snappy() {
    // Step 1: Build snappy
    // ----------------------------------------------------------------------
    let snappy_path = Path::new("deps")
                           .join(format!("snappy-{}", SNAPPY_VERSION));

    // Clean the build directory first.
    println!("[snappy] Cleaning");
    Command::new("make").args(&["-C", snappy_path.to_str().unwrap()])
                        .arg("distclean")
                        .status().ok().expect("make distclean failed");

    // Configure the build
    println!("[snappy] Configuring");
    Command::new("./configure").current_dir(&snappy_path)
                               .arg("CXXFLAGS=-fPIC")
                               .status().ok().expect("configure failed");

    // Call "make" to build the C library
    println!("[snappy] Building");
    Command::new("make").args(&["-C", snappy_path.to_str().unwrap()])
                        .status().ok().expect("make failed");

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&snappy_path.join(".libs").join("libsnappy.a"), &out_dir.join("libsnappy.a"));
    res.ok().expect("copy of output files failed");
}

fn build_leveldb(with_snappy: bool) {
    // Step 1: Build LevelDB
    // ----------------------------------------------------------------------
    let leveldb_path = Path::new("deps")
                            .join(format!("leveldb-{}", LEVELDB_VERSION));

    // Clean the build directory first.
    println!("[leveldb] Cleaning");
    Command::new("make").args(&["-C", leveldb_path.to_str().unwrap()])
                        .arg("clean")
                        .status().ok().expect("clean failed");

    // Set up the process environment.  We essentially clone the existing
    // environment, and, if we're including Snappy, also include the appropriate
    // CXXFLAGS and LDFLAGS variables.
    let mut env_map: HashMap<OsString, OsString> = env::vars().map(|(k, v)| {
        (
            k.into(),
            v.into()
        )
    }).collect();

    if with_snappy {
        let linker_path = env::var("OUT_DIR").unwrap();
        env_map.insert(
            "LDFLAGS".into(),
            format!("-L{}", linker_path).into()
        );

        let snappy_path = Path::new("deps")
                               .join(format!("snappy-{}", SNAPPY_VERSION));
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-I{} -fPIC", snappy_path.to_str().unwrap()).into()
        );
    } else {
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-fPIC").into()
        );
    }

    let mut cmd = Command::new("make");

    println!("[leveldb] Building command");

    // Convert to the format that `env_set_all` is expecting.
    for (k,v) in env_map.into_iter() {
        cmd.env(k,v);
    }

    let path_arg = leveldb_path.to_str().expect("leveldb path is not a string");

    // Build the library
    println!("[leveldb] Building");
    cmd.args(&["-C", path_arg])
       .status().ok().expect("leveldb build failed");

    println!("[leveldb] Build finished");
    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&leveldb_path.join("libleveldb.a"), &out_dir.join("libleveldb.a"));
    res.ok().expect("copy of output files failed");
}

fn main() {
    println!("[build] Started");

    let have_snappy = env::var("CARGO_FEATURE_SNAPPY").is_ok();

    // If we have the appropriate feature, then we build snappy.
    if have_snappy {
        build_snappy();
    }

    // Copy the build_detect_platform file into the appropriate place.
    let template_path = Path::new("deps")
                             .join("build_detect_platform");
    let detect_path = Path::new("deps")
                           .join(format!("leveldb-{}", LEVELDB_VERSION))
                           .join("build_detect_platform");
    if have_snappy {
        println!("[build] Copying the `build_detect_platform` template");
        fs::copy(&template_path, &detect_path).unwrap();
    } else {
        println!("[build] Patching the `build_detect_platform` template");

        // If we aren't using snappy, remove the lines from
        // build_detect_platform that enable Snappy.  This prevents us from
        // picking up a system-local copy of Snappy.
        let new_lines: Vec<String> = {
            let file = File::open(&template_path).unwrap();
            let reader = BufReader::new(file);

            reader.lines().map(|line| {
                let line = line.unwrap();
                if line.contains("-DSNAPPY") || line.contains("-lsnappy") {
                    let mut tmp = String::new();
                    tmp.push_str("true   #");
                    tmp.push_str(line.as_ref());
                    tmp.push_str("\n");
                    tmp
                } else {
                    line
                }
            }).collect()
        };

        let mut f = File::create(&detect_path).unwrap();
        for line in new_lines.iter() {
            f.write_all(line.as_ref()).ok().expect("writing a line failed");
            f.write_all("\n".as_bytes()).ok().expect("writing a line failed");
        }

        println!("[build] Patching complete");
    }

    // Set executable bits on the file

    let mut perms = fs::metadata(&detect_path).ok().expect("metadata missing").permissions();
    let current_mode = perms.mode();
    perms.set_mode(0o100 | current_mode);
    fs::set_permissions(&detect_path, perms).ok().expect("permissions could not be set");

    // Build LevelDB
    build_leveldb(have_snappy);

    // Print the appropriate linker flags
    let out_dir = env::var("OUT_DIR").ok().expect("OUT_DIR missing");
    let linker_flags = if have_snappy {
        "-l static=snappy -l static=leveldb -l stdc++"
    } else {
        "-l static=leveldb -l stdc++"
    };
    println!("cargo:rustc-flags=-L native={} {} -l stdc++", out_dir, linker_flags);

    println!("[build] Finished");
}
<commit_msg>Fix the build fails to link on macOS Sierra.<commit_after>use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::fs;
use std::env;
use std::os::unix::fs::PermissionsExt;
use std::io::{Write,BufReader};
use std::io::BufRead;
use std::process::Command;
use std::path::Path;

const SNAPPY_VERSION: &'static str  = "1.1.2";
const LEVELDB_VERSION: &'static str = "1.18";

fn build_snappy() {
    // Step 1: Build snappy
    // ----------------------------------------------------------------------
    let snappy_path = Path::new("deps")
                           .join(format!("snappy-{}", SNAPPY_VERSION));

    // Clean the build directory first.
    println!("[snappy] Cleaning");
    Command::new("make").args(&["-C", snappy_path.to_str().unwrap()])
                        .arg("distclean")
                        .status().ok().expect("make distclean failed");

    // Configure the build
    println!("[snappy] Configuring");
    Command::new("./configure").current_dir(&snappy_path)
                               .arg("CXXFLAGS=-fPIC")
                               .status().ok().expect("configure failed");

    // Call "make" to build the C library
    println!("[snappy] Building");
    Command::new("make").args(&["-C", snappy_path.to_str().unwrap()])
                        .status().ok().expect("make failed");

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&snappy_path.join(".libs").join("libsnappy.a"), &out_dir.join("libsnappy.a"));
    res.ok().expect("copy of output files failed");
}

fn build_leveldb(with_snappy: bool) {
    // Step 1: Build LevelDB
    // ----------------------------------------------------------------------
    let leveldb_path = Path::new("deps")
                            .join(format!("leveldb-{}", LEVELDB_VERSION));

    // Clean the build directory first.
    println!("[leveldb] Cleaning");
    Command::new("make").args(&["-C", leveldb_path.to_str().unwrap()])
                        .arg("clean")
                        .status().ok().expect("clean failed");

    // Set up the process environment.  We essentially clone the existing
    // environment, and, if we're including Snappy, also include the appropriate
    // CXXFLAGS and LDFLAGS variables.
    let mut env_map: HashMap<OsString, OsString> = env::vars().map(|(k, v)| {
        (
            k.into(),
            v.into()
        )
    }).collect();

    if with_snappy {
        let linker_path = env::var("OUT_DIR").unwrap();
        env_map.insert(
            "LDFLAGS".into(),
            format!("-L{}", linker_path).into()
        );

        let snappy_path = Path::new("deps")
                               .join(format!("snappy-{}", SNAPPY_VERSION));
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-I{} -fPIC", snappy_path.to_str().unwrap()).into()
        );
    } else {
        env_map.insert(
            "CXXFLAGS".into(),
            format!("-fPIC").into()
        );
    }

    let mut cmd = Command::new("make");

    println!("[leveldb] Building command");

    // Convert to the format that `env_set_all` is expecting.
    for (k,v) in env_map.into_iter() {
        cmd.env(k,v);
    }

    let path_arg = leveldb_path.to_str().expect("leveldb path is not a string");

    // Build the library
    println!("[leveldb] Building");
    cmd.args(&["-C", path_arg])
       .status().ok().expect("leveldb build failed");

    println!("[leveldb] Build finished");
    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let env_var = &env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(env_var);

    println!("[build] Copying output files");
    let res = fs::copy(&leveldb_path.join("libleveldb.a"), &out_dir.join("libleveldb.a"));
    res.ok().expect("copy of output files failed");
}

fn main() {
    println!("[build] Started");

    let have_snappy = env::var("CARGO_FEATURE_SNAPPY").is_ok();

    // If we have the appropriate feature, then we build snappy.
    if have_snappy {
        build_snappy();
    }

    // Copy the build_detect_platform file into the appropriate place.
    let template_path = Path::new("deps")
                             .join("build_detect_platform");
    let detect_path = Path::new("deps")
                           .join(format!("leveldb-{}", LEVELDB_VERSION))
                           .join("build_detect_platform");
    if have_snappy {
        println!("[build] Copying the `build_detect_platform` template");
        fs::copy(&template_path, &detect_path).unwrap();
    } else {
        println!("[build] Patching the `build_detect_platform` template");

        // If we aren't using snappy, remove the lines from
        // build_detect_platform that enable Snappy.  This prevents us from
        // picking up a system-local copy of Snappy.
        let new_lines: Vec<String> = {
            let file = File::open(&template_path).unwrap();
            let reader = BufReader::new(file);

            reader.lines().map(|line| {
                let line = line.unwrap();
                if line.contains("-DSNAPPY") || line.contains("-lsnappy") {
                    let mut tmp = String::new();
                    tmp.push_str("true   #");
                    tmp.push_str(line.as_ref());
                    tmp.push_str("\n");
                    tmp
                } else {
                    line
                }
            }).collect()
        };

        let mut f = File::create(&detect_path).unwrap();
        for line in new_lines.iter() {
            f.write_all(line.as_ref()).ok().expect("writing a line failed");
            f.write_all("\n".as_bytes()).ok().expect("writing a line failed");
        }

        println!("[build] Patching complete");
    }

    // Set executable bits on the file

    let mut perms = fs::metadata(&detect_path).ok().expect("metadata missing").permissions();
    let current_mode = perms.mode();
    perms.set_mode(0o100 | current_mode);
    fs::set_permissions(&detect_path, perms).ok().expect("permissions could not be set");

    // Build LevelDB
    build_leveldb(have_snappy);

    // Print the appropriate linker flags
    let out_dir = env::var("OUT_DIR").ok().expect("OUT_DIR missing");
    let linker_flags = if have_snappy {
        "-l static=snappy -l static=leveldb"
    } else {
        "-l static=leveldb"
    };
    println!("cargo:rustc-flags=-L native={} {}", out_dir, linker_flags);

    let target = env::var("TARGET").unwrap();
    if target.contains("apple") {
        println!("cargo:rustc-link-lib=c++");
    } else {
        println!("cargo:rustc-link-lib=stdc++");
    }

    println!("[build] Finished");
}
<|endoftext|>


<commit_before>use mem_map::MEM_PAGE_SIZE_BYTES;
use mem_map::{Frame,FrameAllocator};

use super::ENTRY_COUNT;
use super::VirtualAddress;
use super::mapper::Mapper;
use super::table::*;
use super::page_table::ActivePageTable;
use super::mapper;
use super::entry::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Page {
   pub index: usize,
}

impl Page {
    pub fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000, "invalid address: 0x{:x}", address);
        Page { index: address / MEM_PAGE_SIZE_BYTES }
    }

    pub fn start_address(&self) -> usize {
        self.index * MEM_PAGE_SIZE_BYTES
    }

    pub fn p4_index(&self) -> usize {
        (self.index >> 27) & 0o777
    }
    pub fn p3_index(&self) -> usize {
        (self.index >> 18) & 0o777
    }
    pub fn p2_index(&self) -> usize {
        (self.index >> 9) & 0o777
    }
    pub fn p1_index(&self) -> usize {
        (self.index >> 0) & 0o777
    }

    pub fn translate(&self) -> Option<Frame> {
        let p3 = unsafe { &*mapper::P4 }.next_table(self.p4_index());

        let huge_page = || {
            p3.and_then(|p3| {
                let p3_entry = &p3[self.p3_index()];
                // 1GiB self?
                if let Some(start_frame) = p3_entry.pointed_frame() {
                    if p3_entry.flags().contains(HUGE_PAGE) {
                        // address must be 1GiB aligned
                        assert!(start_frame.index % (ENTRY_COUNT * ENTRY_COUNT) == 0);
                        return Some(Frame {
                            index: start_frame.index + self.p2_index() * ENTRY_COUNT + self.p1_index()
                        });
                    }
                }
                if let Some(p2) = p3.next_table(self.p3_index()) {
                    let p2_entry = &p2[self.p2_index()];
                    // 2MiB self?
                    if let Some(start_frame) = p2_entry.pointed_frame() {
                        if p2_entry.flags().contains(HUGE_PAGE) {
                            // address must be 2MiB aligned
                            assert!(start_frame.index % ENTRY_COUNT == 0);
                            return Some(Frame { index: start_frame.index + self.p1_index() });
                        }
                    }
                }
                None
            })
        };

        p3.and_then(|p3| p3.next_table(self.p3_index()))
          .and_then(|p2| p2.next_table(self.p2_index()))
          .and_then(|p1| p1[self.p1_index()].pointed_frame())
          .or_else(huge_page)
    }
    pub fn range_inclusive(start: Page, end: Page) -> PageIter {
        PageIter {
            start: start,
            end: end,
        }
    }
}

pub struct PageIter {
    start: Page,
    end: Page,
}

impl Iterator for PageIter {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start <= self.end {
            let page = self.start;
            self.start.index += 1;
            Some(page)
        } else {
            None
        }
    }
}

struct TinyAllocator([Option<Frame>; 3]);
impl TinyAllocator {
    fn new<A>(allocator: &mut A) -> TinyAllocator where A: FrameAllocator
    {
        let mut f = || allocator.allocate_frame();
        let frames = [f(), f(), f()];
        TinyAllocator(frames)
    }
}
impl FrameAllocator for TinyAllocator {
    fn allocate_frame(&mut self) -> Option<Frame> {
        for frame_option in &mut self.0 {
            if frame_option.is_some() {
                return frame_option.take();
            }
        }
        None
    }

    fn deallocate_frame(&mut self, frame: Frame) {
        for frame_option in &mut self.0 {
            if frame_option.is_none() {
                *frame_option = Some(frame);
                return;
            }
        }
        panic!("Tiny allocator can hold only 3 frames.");
    }
}

pub struct TemporaryPage {
    page: Page,
    allocator: TinyAllocator,
}
impl TemporaryPage {
    pub fn new<A>(page: Page, allocator: &mut A) -> TemporaryPage where A: FrameAllocator {
        TemporaryPage {
            page: page,
            allocator: TinyAllocator::new(allocator),
        }
    }
    /// Maps the temporary page to the given frame in the active table.
    /// Returns the start address of the temporary page.
    pub fn map(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> VirtualAddress {
        // XXX: kludge fix??? tutorial doens't seem to have same problem
        // assert!(active_table.translate_page(self.page).is_none(), "temporary page is already mapped");
        assert!(active_table.translate_page(self.page.index).is_none(), "temporary page is already mapped");

        active_table.map_to(self.page, frame, WRITABLE, &mut self.allocator);
        self.page.start_address()
    }

    pub fn map_table_frame(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> &mut Table<Level1> {
        unsafe { &mut *(self.map(frame, active_table) as *mut Table<Level1>) }
    }

    /// Unmaps the temporary page in the active table.
    pub fn unmap(&mut self, active_table: &mut Mapper) {
        active_table.unmap(self.page, &mut self.allocator)
    }
}
<commit_msg>Typofix<commit_after>use mem_map::MEM_PAGE_SIZE_BYTES;
use mem_map::{Frame,FrameAllocator};

use super::ENTRY_COUNT;
use super::VirtualAddress;
use super::mapper::Mapper;
use super::table::*;
use super::page_table::ActivePageTable;
use super::mapper;
use super::entry::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Page {
   pub index: usize,
}

impl Page {
    pub fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000, "invalid address: 0x{:x}", address);
        Page { index: address / MEM_PAGE_SIZE_BYTES }
    }

    pub fn start_address(&self) -> usize {
        self.index * MEM_PAGE_SIZE_BYTES
    }

    pub fn p4_index(&self) -> usize {
        (self.index >> 27) & 0o777
    }
    pub fn p3_index(&self) -> usize {
        (self.index >> 18) & 0o777
    }
    pub fn p2_index(&self) -> usize {
        (self.index >> 9) & 0o777
    }
    pub fn p1_index(&self) -> usize {
        (self.index >> 0) & 0o777
    }

    pub fn translate(&self) -> Option<Frame> {
        let p3 = unsafe { &*mapper::P4 }.next_table(self.p4_index());

        let huge_page = || {
            p3.and_then(|p3| {
                let p3_entry = &p3[self.p3_index()];
                // 1GiB self?
                if let Some(start_frame) = p3_entry.pointed_frame() {
                    if p3_entry.flags().contains(HUGE_PAGE) {
                        // address must be 1GiB aligned
                        assert!(start_frame.index % (ENTRY_COUNT * ENTRY_COUNT) == 0);
                        return Some(Frame {
                            index: start_frame.index + self.p2_index() * ENTRY_COUNT + self.p1_index()
                        });
                    }
                }
                if let Some(p2) = p3.next_table(self.p3_index()) {
                    let p2_entry = &p2[self.p2_index()];
                    // 2MiB self?
                    if let Some(start_frame) = p2_entry.pointed_frame() {
                        if p2_entry.flags().contains(HUGE_PAGE) {
                            // address must be 2MiB aligned
                            assert!(start_frame.index % ENTRY_COUNT == 0);
                            return Some(Frame { index: start_frame.index + self.p1_index() });
                        }
                    }
                }
                None
            })
        };

        p3.and_then(|p3| p3.next_table(self.p3_index()))
          .and_then(|p2| p2.next_table(self.p2_index()))
          .and_then(|p1| p1[self.p1_index()].pointed_frame())
          .or_else(huge_page)
    }
    pub fn range_inclusive(start: Page, end: Page) -> PageIter {
        PageIter {
            start: start,
            end: end,
        }
    }
}

pub struct PageIter {
    start: Page,
    end: Page,
}

impl Iterator for PageIter {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        if self.start <= self.end {
            let page = self.start;
            self.start.index += 1;
            Some(page)
        } else {
            None
        }
    }
}

struct TinyAllocator([Option<Frame>; 3]);
impl TinyAllocator {
    fn new<A>(allocator: &mut A) -> TinyAllocator where A: FrameAllocator
    {
        let mut f = || allocator.allocate_frame();
        let frames = [f(), f(), f()];
        TinyAllocator(frames)
    }
}
impl FrameAllocator for TinyAllocator {
    fn allocate_frame(&mut self) -> Option<Frame> {
        for frame_option in &mut self.0 {
            if frame_option.is_some() {
                return frame_option.take();
            }
        }
        None
    }

    fn deallocate_frame(&mut self, frame: Frame) {
        for frame_option in &mut self.0 {
            if frame_option.is_none() {
                *frame_option = Some(frame);
                return;
            }
        }
        panic!("Tiny allocator can hold only 3 frames.");
    }
}

pub struct TemporaryPage {
    page: Page,
    allocator: TinyAllocator,
}
impl TemporaryPage {
    pub fn new<A>(page: Page, allocator: &mut A) -> TemporaryPage where A: FrameAllocator {
        TemporaryPage {
            page: page,
            allocator: TinyAllocator::new(allocator),
        }
    }
    /// Maps the temporary page to the given frame in the active table.
    /// Returns the start address of the temporary page.
    pub fn map(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> VirtualAddress {
        // XXX: kludge fix??? tutorial doesn't seem to have same problem
        // assert!(active_table.translate_page(self.page).is_none(), "temporary page is already mapped");
        assert!(active_table.translate_page(self.page.index).is_none(), "temporary page is already mapped");

        active_table.map_to(self.page, frame, WRITABLE, &mut self.allocator);
        self.page.start_address()
    }

    pub fn map_table_frame(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> &mut Table<Level1> {
        unsafe { &mut *(self.map(frame, active_table) as *mut Table<Level1>) }
    }

    /// Unmaps the temporary page in the active table.
    pub fn unmap(&mut self, active_table: &mut Mapper) {
        active_table.unmap(self.page, &mut self.allocator)
    }
}
<|endoftext|>


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

use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Display;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;

use dbus;
use dbus::Connection;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;

use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MethodFn;
use dbus::tree::MethodResult;
use dbus::tree::Property;
use dbus::tree::Tree;

use dbus_consts::*;

use engine::Engine;
use pool::StratisPool;
use types::{StratisResult, StratisError};

#[derive(Debug, Clone)]
pub struct DbusContext<'a> {
    name_prop: Arc<Property<MethodFn<'a>>>,
    pub remaining_prop: Arc<Property<MethodFn<'a>>>,
    pub total_prop: Arc<Property<MethodFn<'a>>>,
    pub status_prop: Arc<Property<MethodFn<'a>>>,
    pub running_status_prop: Arc<Property<MethodFn<'a>>>,
    pub block_devices_prop: Arc<Property<MethodFn<'a>>>,
}

impl<'a> DbusContext<'a> {
    pub fn update_one(prop: &Arc<Property<MethodFn<'a>>>, m: MessageItem) -> StratisResult<()> {
        match prop.set_value(m) {
            Ok(_) => Ok(()), // TODO: return signals
            Err(()) => Err(StratisError::Dbus(dbus::Error::new_custom(
                "UpdateError", "Could not update property with value"))),
        }
    }
}

fn list_pools(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let result = engine.borrow().list_pools();

    let mut msg_vec = Vec::new();

    // TODO: deal with failure
    let pool_tree = result.unwrap();

    for (name, pool) in pool_tree {
        let entry = vec![MessageItem::Str(format!("{}", name)),
                         MessageItem::UInt16(0),
                         MessageItem::Str(String::from("Ok"))];
        msg_vec.push(MessageItem::Struct(entry));
    }

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));

    Ok(vec![m.method_return().append1(item_array)])
}

fn create_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let raid_level: u16 = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner()
                .map_err(|_| MethodErr::invalid_arg(&i))
        }));

    let devs = match try!(items.pop().ok_or_else(MethodErr::no_arg)) {
        MessageItem::Array(x, _) => x,
        x => return Err(MethodErr::invalid_arg(&x)),
    };

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let blockdevs = devs.into_iter()
        .map(|x| PathBuf::from(x.inner::<&str>().unwrap()))
        .collect::<Vec<_>>();

    let result = engine.borrow_mut().create_pool(&name, &blockdevs, raid_level);

    Ok(vec![m.method_return().append3("/dbus/newpool/path", 0, "Ok")])
}

fn destroy_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let name = try!(m.get1::<String>().ok_or_else(MethodErr::no_arg));

    let result = engine.borrow_mut().destroy_pool(&name);

    let message = m.method_return();

    let msg = match result {
        Ok(_) => {
            message.append2(MessageItem::UInt16(0),
                            MessageItem::Str(format!("{}", "Ok")))
        }
        Err(err) => {
            message.append2(MessageItem::UInt16(0),
                            MessageItem::Str(format!("{}", "Ok")))
        }
    };

    Ok(vec![msg])

}

fn get_pool_object_path(m: &Message) -> MethodResult {

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn get_volume_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/volume/path", 0, "Ok")])
}

fn get_dev_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/dev/path", 0, "Ok")])
}

fn get_cache_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/cache/path", 0, "Ok")])
}

fn get_list_items<T, I>(m: &Message, iter: I) -> MethodResult
    where T: HasCodes + Display,
          I: Iterator<Item = T>
{
    let msg_vec = iter.map(|item| {
            MessageItem::Struct(vec![MessageItem::Str(format!("{}", item)),
                                     MessageItem::UInt16(item.get_error_int()),
                                     MessageItem::Str(format!("{}", item.get_error_string()))])
        })
        .collect::<Vec<MessageItem>>();

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));
    Ok(vec![m.method_return().append1(item_array)])
}

fn get_error_codes(m: &Message) -> MethodResult {
    get_list_items(m, StratisErrorEnum::iter_variants())
}

fn get_raid_levels(m: &Message) -> MethodResult {
    get_list_items(m, StratisRaidType::iter_variants())
}

fn get_dev_types(m: &Message) -> MethodResult {
    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let _name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    println!("method called");

    Ok(vec![m.method_return()])
}

pub fn get_base_tree<'a>(c: &'a Connection,
                         engine: Rc<RefCell<Engine>>)
                         -> StratisResult<Tree<MethodFn<'a>>> {
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32).unwrap();

    let f = Factory::new_fn();

    let base_tree = f.tree();

    let engine_clone = engine.clone();

    let createpool_method = f.method(CREATE_POOL, move |m, _, _| create_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .in_arg(("dev_list", "as"))
        .in_arg(("raid_type", "q"))
        .out_arg(("object_path", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let destroypool_method = f.method(DESTROY_POOL, move |m, _, _| destroy_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let listpools_method = f.method(LIST_POOLS, move |m, _, _| list_pools(m, &engine_clone))
        .out_arg(("pool_names", "as"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getpoolobjectpath_method =
        f.method(GET_POOL_OBJECT_PATH, move |m, _, _| get_pool_object_path(m))
            .in_arg(("pool_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getvolumeobjectpath_method = f.method(GET_VOLUME_OBJECT_PATH,
                move |m, _, _| get_volume_object_path(m))
        .in_arg(("pool_name", "s"))
        .in_arg(("volume_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getdevobjectpath_method =
        f.method(GET_DEV_OBJECT_PATH, move |m, _, _| get_dev_object_path(m))
            .in_arg(("dev_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getcacheobjectpath_method = f.method(GET_CACHE_OBJECT_PATH,
                move |m, _, _| get_cache_object_path(m))
        .in_arg(("cache_dev_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let geterrorcodes_method = f.method(GET_ERROR_CODES, move |m, _, _| get_error_codes(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getraidlevels_method = f.method(GET_RAID_LEVELS, move |m, _, _| get_raid_levels(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getdevtypes_method = f.method(GET_DEV_TYPES, move |m, _, _| get_dev_types(m));

    let obj_path = f.object_path(STRATIS_BASE_PATH)
        .introspectable()
        .add(f.interface(STRATIS_MANAGER_INTERFACE)
            .add_m(listpools_method)
            .add_m(createpool_method)
            .add_m(destroypool_method)
            .add_m(getpoolobjectpath_method)
            .add_m(getvolumeobjectpath_method)
            .add_m(getdevobjectpath_method)
            .add_m(getcacheobjectpath_method)
            .add_m(geterrorcodes_method)
            .add_m(getraidlevels_method)
            .add_m(getdevtypes_method));

    let base_tree = base_tree.add(obj_path);
    try!(base_tree.set_registered(c, true));

    Ok(base_tree)
}
<commit_msg>Avoid torpedo notation.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt::Display;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;

use dbus;
use dbus::Connection;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;

use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MethodFn;
use dbus::tree::MethodResult;
use dbus::tree::Property;
use dbus::tree::Tree;

use dbus_consts::*;

use engine::Engine;
use pool::StratisPool;
use types::{StratisResult, StratisError};

#[derive(Debug, Clone)]
pub struct DbusContext<'a> {
    name_prop: Arc<Property<MethodFn<'a>>>,
    pub remaining_prop: Arc<Property<MethodFn<'a>>>,
    pub total_prop: Arc<Property<MethodFn<'a>>>,
    pub status_prop: Arc<Property<MethodFn<'a>>>,
    pub running_status_prop: Arc<Property<MethodFn<'a>>>,
    pub block_devices_prop: Arc<Property<MethodFn<'a>>>,
}

impl<'a> DbusContext<'a> {
    pub fn update_one(prop: &Arc<Property<MethodFn<'a>>>, m: MessageItem) -> StratisResult<()> {
        match prop.set_value(m) {
            Ok(_) => Ok(()), // TODO: return signals
            Err(()) => Err(StratisError::Dbus(dbus::Error::new_custom(
                "UpdateError", "Could not update property with value"))),
        }
    }
}

fn list_pools(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let result = engine.borrow().list_pools();

    let mut msg_vec = Vec::new();

    // TODO: deal with failure
    let pool_tree = result.unwrap();

    for (name, pool) in pool_tree {
        let entry = vec![MessageItem::Str(format!("{}", name)),
                         MessageItem::UInt16(0),
                         MessageItem::Str(String::from("Ok"))];
        msg_vec.push(MessageItem::Struct(entry));
    }

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));

    Ok(vec![m.method_return().append1(item_array)])
}

fn create_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let raid_level: u16 = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner()
                .map_err(|_| MethodErr::invalid_arg(&i))
        }));

    let devs = match try!(items.pop().ok_or_else(MethodErr::no_arg)) {
        MessageItem::Array(x, _) => x,
        x => return Err(MethodErr::invalid_arg(&x)),
    };

    // Get the name of the pool from the parameters
    let name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    let blockdevs = devs.into_iter()
        .map(|x| PathBuf::from(x.inner::<&str>().unwrap()))
        .collect::<Vec<_>>();

    let result = engine.borrow_mut().create_pool(&name, &blockdevs, raid_level);

    Ok(vec![m.method_return().append3("/dbus/newpool/path", 0, "Ok")])
}

fn destroy_pool(m: &Message, engine: &Rc<RefCell<Engine>>) -> MethodResult {

    let name: String = try!(m.get1().ok_or_else(MethodErr::no_arg));

    let result = engine.borrow_mut().destroy_pool(&name);

    let message = m.method_return();

    let msg = match result {
        Ok(_) => {
            message.append2(MessageItem::UInt16(0),
                            MessageItem::Str(format!("{}", "Ok")))
        }
        Err(err) => {
            message.append2(MessageItem::UInt16(0),
                            MessageItem::Str(format!("{}", "Ok")))
        }
    };

    Ok(vec![msg])

}

fn get_pool_object_path(m: &Message) -> MethodResult {

    Ok(vec![m.method_return().append3("/dbus/pool/path", 0, "Ok")])
}

fn get_volume_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/volume/path", 0, "Ok")])
}

fn get_dev_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/dev/path", 0, "Ok")])
}

fn get_cache_object_path(m: &Message) -> MethodResult {
    Ok(vec![m.method_return().append3("/dbus/cache/path", 0, "Ok")])
}

fn get_list_items<T, I>(m: &Message, iter: I) -> MethodResult
    where T: HasCodes + Display,
          I: Iterator<Item = T>
{
    let msg_vec = iter.map(|item| {
            MessageItem::Struct(vec![MessageItem::Str(format!("{}", item)),
                                     MessageItem::UInt16(item.get_error_int()),
                                     MessageItem::Str(format!("{}", item.get_error_string()))])
        })
        .collect::<Vec<MessageItem>>();

    let item_array = MessageItem::Array(msg_vec, Cow::Borrowed("(sqs)"));
    Ok(vec![m.method_return().append1(item_array)])
}

fn get_error_codes(m: &Message) -> MethodResult {
    get_list_items(m, StratisErrorEnum::iter_variants())
}

fn get_raid_levels(m: &Message) -> MethodResult {
    get_list_items(m, StratisRaidType::iter_variants())
}

fn get_dev_types(m: &Message) -> MethodResult {
    let mut items = m.get_items();
    if items.len() < 1 {
        return Err(MethodErr::no_arg());
    }

    let _name = try!(items.pop()
        .ok_or_else(MethodErr::no_arg)
        .and_then(|i| {
            i.inner::<&str>()
                .map_err(|_| MethodErr::invalid_arg(&i))
                .map(|i| i.to_owned())
        }));

    println!("method called");

    Ok(vec![m.method_return()])
}

pub fn get_base_tree<'a>(c: &'a Connection,
                         engine: Rc<RefCell<Engine>>)
                         -> StratisResult<Tree<MethodFn<'a>>> {
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32).unwrap();

    let f = Factory::new_fn();

    let base_tree = f.tree();

    let engine_clone = engine.clone();

    let createpool_method = f.method(CREATE_POOL, move |m, _, _| create_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .in_arg(("dev_list", "as"))
        .in_arg(("raid_type", "q"))
        .out_arg(("object_path", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let destroypool_method = f.method(DESTROY_POOL, move |m, _, _| destroy_pool(m, &engine_clone))
        .in_arg(("pool_name", "s"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let engine_clone = engine.clone();

    let listpools_method = f.method(LIST_POOLS, move |m, _, _| list_pools(m, &engine_clone))
        .out_arg(("pool_names", "as"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getpoolobjectpath_method =
        f.method(GET_POOL_OBJECT_PATH, move |m, _, _| get_pool_object_path(m))
            .in_arg(("pool_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getvolumeobjectpath_method = f.method(GET_VOLUME_OBJECT_PATH,
                move |m, _, _| get_volume_object_path(m))
        .in_arg(("pool_name", "s"))
        .in_arg(("volume_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let getdevobjectpath_method =
        f.method(GET_DEV_OBJECT_PATH, move |m, _, _| get_dev_object_path(m))
            .in_arg(("dev_name", "s"))
            .out_arg(("object_path", "o"))
            .out_arg(("return_code", "q"))
            .out_arg(("return_string", "s"));

    let getcacheobjectpath_method = f.method(GET_CACHE_OBJECT_PATH,
                move |m, _, _| get_cache_object_path(m))
        .in_arg(("cache_dev_name", "s"))
        .out_arg(("object_path", "o"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let geterrorcodes_method = f.method(GET_ERROR_CODES, move |m, _, _| get_error_codes(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getraidlevels_method = f.method(GET_RAID_LEVELS, move |m, _, _| get_raid_levels(m))
        .out_arg(("error_codes", "a(sqs)"));

    let getdevtypes_method = f.method(GET_DEV_TYPES, move |m, _, _| get_dev_types(m));

    let obj_path = f.object_path(STRATIS_BASE_PATH)
        .introspectable()
        .add(f.interface(STRATIS_MANAGER_INTERFACE)
            .add_m(listpools_method)
            .add_m(createpool_method)
            .add_m(destroypool_method)
            .add_m(getpoolobjectpath_method)
            .add_m(getvolumeobjectpath_method)
            .add_m(getdevobjectpath_method)
            .add_m(getcacheobjectpath_method)
            .add_m(geterrorcodes_method)
            .add_m(getraidlevels_method)
            .add_m(getdevtypes_method));

    let base_tree = base_tree.add(obj_path);
    try!(base_tree.set_registered(c, true));

    Ok(base_tree)
}
<|endoftext|>


<commit_before>use node::{ Expr };
use parser::{ Parse, Context };
use { Token, TokenValue };
use operator::{ OperatorOptions, OperatorKind, Associativity };
use error::{ Error, ErrorMessage };
use { Result, Expect };

impl<'c> Parse<'c> for Expr<'c> {
    type Output = Expr<'c>;

    fn parse<'r, I>(parser: &mut Context<'r, I>)
        -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
    {
        parse_expression(parser, 0)
    }
}

fn parse_expression<'p, 'c, I>(parser: &mut Context<'p, I>, min_precedence: u16)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_expression");

    let mut expr = try!(get_primary(parser));
    let mut token = try!(parser.current());

    loop {
        if let TokenValue::Operator(op_str) = token.value {
            if let OperatorOptions { kind: OperatorKind::Binary(associativity), precedence, .. } = *parser.get_operator_options(op_str) {
                if precedence >= min_precedence {
                    try!(parser.next());

                    // if callable ...
                        // TODO: Callable.
                    // else
                    let expr1 = try!(parse_expression(parser, match associativity {
                        Associativity::Left => precedence + 1,
                        Associativity::Right => precedence,
                    }));
                    expr = Expr::BinaryOperator {
                        value: op_str,
                        left: Box::new(expr.clone()),
                        right: Box::new(expr1),
                        line: token.line
                    };
                    // endif

                    token = try!(parser.current());

                    continue;
                }
            }
        }
        break;
    }

    if 0 == min_precedence {
        return parse_conditional_expression(parser, expr);
    }

    Ok(expr)
}

/// Parses expression and returns handle to one that should be executed first.
fn get_primary<'p, 'c, I>(parser: &mut Context<'p, I>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    let token = try!(parser.current());

    if let TokenValue::Operator(op_str) = token.value {
        if let OperatorOptions { kind: OperatorKind::Unary, precedence, .. } = *parser.get_operator_options(op_str) {
            try!(parser.next());
            let expr = try!(parse_expression(parser, precedence));
            let parsed_expr = Expr::UnaryOperator {
                value: op_str,
                expr: Box::new(expr),
                line: token.line
            };
            return parse_postfix_expression(parser, parsed_expr);
        }
    }

    if let TokenValue::Punctuation('(') = token.value {
        try!(parser.next());
        let parsed_expr = try!(parse_expression(parser, 0));
        if let Err(_) = parser.tokens.expect(TokenValue::Punctuation(')')) {
            return Err(Error::new_at(ErrorMessage::ParenthesisNotClosed, token.line));
        }
        return parse_postfix_expression(parser, parsed_expr);
    }

    parse_primary_expression(parser)
}

/// Parses expression and returns handle to one that should be executed first.
fn parse_primary_expression<'p, 'c, I>(parser: &mut Context<'p, I>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_primary_expression");
    let token = try!(parser.current());

    match token.value {
        TokenValue::Name(_) => unreachable!("TokenValue::Name"),
        TokenValue::Value(_) => unreachable!("TokenValue::Value"),
        TokenValue::InterpolationStart => unreachable!("TokenValue::InterpolationStart"),
        TokenValue::Operator(_) => unreachable!("TokenValue::Operator"),
        TokenValue::Punctuation('[') => unreachable!("TokenValue::Punctuation('[')"),
        TokenValue::Punctuation('{') => unreachable!("TokenValue::Punctuation('{')"),
        _ => panic!("uncovered choice! baaah!"),
    }
    unimplemented!()
}

/// Parses expression and returns handle to one that should be executed first.
fn parse_postfix_expression<'p, 'c, I>(parser: &mut Context<'p, I>, expr: Expr<'c>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_postfix_expression");
    unimplemented!()
}

fn parse_conditional_expression<'p, 'c, I>(parser: &mut Context<'p, I>, expr: Expr<'c>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_conditional_expression");
    unimplemented!()
}
<commit_msg>Return Unexpected token error.<commit_after>use node::{ Expr };
use parser::{ Parse, Context };
use { Token, TokenValue };
use operator::{ OperatorOptions, OperatorKind, Associativity };
use error::{ Error, ErrorMessage };
use { Result, Expect };

impl<'c> Parse<'c> for Expr<'c> {
    type Output = Expr<'c>;

    fn parse<'r, I>(parser: &mut Context<'r, I>)
        -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
    {
        parse_expression(parser, 0)
    }
}

fn parse_expression<'p, 'c, I>(parser: &mut Context<'p, I>, min_precedence: u16)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_expression");

    let mut expr = try!(get_primary(parser));
    let mut token = try!(parser.current());

    loop {
        if let TokenValue::Operator(op_str) = token.value {
            if let OperatorOptions { kind: OperatorKind::Binary(associativity), precedence, .. } = *parser.get_operator_options(op_str) {
                if precedence >= min_precedence {
                    try!(parser.next());

                    // if callable ...
                        // TODO: Callable.
                    // else
                    let expr1 = try!(parse_expression(parser, match associativity {
                        Associativity::Left => precedence + 1,
                        Associativity::Right => precedence,
                    }));
                    expr = Expr::BinaryOperator {
                        value: op_str,
                        left: Box::new(expr.clone()),
                        right: Box::new(expr1),
                        line: token.line
                    };
                    // endif

                    token = try!(parser.current());

                    continue;
                }
            }
        }
        break;
    }

    if 0 == min_precedence {
        return parse_conditional_expression(parser, expr);
    }

    Ok(expr)
}

/// Parses expression and returns handle to one that should be executed first.
fn get_primary<'p, 'c, I>(parser: &mut Context<'p, I>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    let token = try!(parser.current());

    if let TokenValue::Operator(op_str) = token.value {
        if let OperatorOptions { kind: OperatorKind::Unary, precedence, .. } = *parser.get_operator_options(op_str) {
            try!(parser.next());
            let expr = try!(parse_expression(parser, precedence));
            let parsed_expr = Expr::UnaryOperator {
                value: op_str,
                expr: Box::new(expr),
                line: token.line
            };
            return parse_postfix_expression(parser, parsed_expr);
        }
    }

    if let TokenValue::Punctuation('(') = token.value {
        try!(parser.next());
        let parsed_expr = try!(parse_expression(parser, 0));
        if let Err(_) = parser.tokens.expect(TokenValue::Punctuation(')')) {
            return Err(Error::new_at(ErrorMessage::ParenthesisNotClosed, token.line));
        }
        return parse_postfix_expression(parser, parsed_expr);
    }

    parse_primary_expression(parser)
}

/// Parses expression and returns handle to one that should be executed first.
fn parse_primary_expression<'p, 'c, I>(parser: &mut Context<'p, I>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_primary_expression");
    let token = try!(parser.current());

    match token.value {
        TokenValue::Name(_) => unreachable!("TokenValue::Name"),
        TokenValue::Value(_) => unreachable!("TokenValue::Value"),
        TokenValue::InterpolationStart => unreachable!("TokenValue::InterpolationStart"),
        TokenValue::Operator(_) => unreachable!("TokenValue::Operator"),
        TokenValue::Punctuation('[') => unreachable!("TokenValue::Punctuation('[')"),
        TokenValue::Punctuation('{') => unreachable!("TokenValue::Punctuation('{')"),
        other => return Err(Error::new_at(
            ErrorMessage::UnexpectedToken(other.into()),
            token.line
        )),
    }
    unimplemented!()
}

/// Parses expression and returns handle to one that should be executed first.
fn parse_postfix_expression<'p, 'c, I>(parser: &mut Context<'p, I>, expr: Expr<'c>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_postfix_expression");
    unimplemented!()
}

fn parse_conditional_expression<'p, 'c, I>(parser: &mut Context<'p, I>, expr: Expr<'c>)
    -> Result<Expr<'c>>
    where
        I: Iterator<Item=Result<Token<'c>>>
{
    println!("parse_conditional_expression");
    unimplemented!()
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::collections::HashMap;
use std::result::Result;
use handle_table::{Handle};
use {EventLoop, TaskReaper};

pub mod promise_node;

thread_local!(pub static EVENT_LOOP: RefCell<Option<EventLoop>> = RefCell::new(None));

pub fn with_current_event_loop<F, R>(f: F) -> R
    where F: FnOnce(&EventLoop) -> R
{
    EVENT_LOOP.with(|maybe_event_loop| {
        match &*maybe_event_loop.borrow() {
            &None => panic!("current thread has no event loop"),
            &Some(ref event_loop) => f(event_loop),
        }
    })
}

pub trait PromiseNode<T, E> {
    /// Arms the given event when the promised value is ready.
    fn on_ready(&mut self, event: EventHandle);

    /// Tells the node that `_self_ptr` is the pointer that owns this node, and will continue to own
    /// this node until it is destroyed or set_self_pointer() is called again. promise_node::Chain uses
    /// this to shorten redundant chains.  The default implementation does nothing; only
    /// promise_node::Chain should implement this.
    fn set_self_pointer(&mut self, _self_ptr: Weak<RefCell<promise_node::ChainState<T, E>>>) {}
    fn get(self: Box<Self>) -> Result<T, E>;
}

pub trait Event {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>>;
}

#[derive(PartialEq, Eq, Copy, Clone, Hash)]
pub struct EventHandle(pub Handle);

impl EventHandle {
    pub fn new() -> (EventHandle, EventDropper) {
        with_current_event_loop(|event_loop| {
            let node = EventNode { event: None, next: None, prev: None };
            let handle = EventHandle(event_loop.events.borrow_mut().push(node));
            (handle, EventDropper { event_handle: handle })
        })
    }

    pub fn set(&self, event: Box<Event>) {
        with_current_event_loop(|event_loop| {
            event_loop.events.borrow_mut()[self.0].event = Some(event);
        })
    }

    pub fn arm_breadth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_breadth_first(self);
        });
    }

    pub fn arm_depth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_depth_first(self);
        });
    }
}

pub struct EventNode {
    pub event: Option<Box<Event>>,
    pub next: Option<EventHandle>,
    pub prev: Option<EventHandle>
}

#[derive(PartialEq, Eq, Hash)]
pub struct EventDropper {
    event_handle: EventHandle,
}

impl Drop for EventDropper {
    fn drop(&mut self) {
        with_current_event_loop(|event_loop| {
            match event_loop.currently_firing.get() {
                Some(h) if h == self.event_handle => panic!("Promise callback destroyed itself."),
                _ => (),
            }
            let maybe_event_node = event_loop.events.borrow_mut().remove(self.event_handle.0);

            match maybe_event_node {
                None => {}
                Some(event_node) => {

                    // event_node.next.prev = event_node.prev
                    match event_node.next {
                        Some(e) => {
                            event_loop.events.borrow_mut()[e.0].prev = event_node.prev;
                        }
                        None => {}
                    }
                    // event_node.prev.next = event_node.next
                    match event_node.prev {
                        Some(e) => {
                            event_loop.events.borrow_mut()[e.0].next = event_node.next;
                            event_loop.tail.set(e);
                        }
                        None => {}
                    }

                    let insertion_point = event_loop.depth_first_insertion_point.get();
                    if insertion_point.0 == self.event_handle.0 {
                        event_loop.depth_first_insertion_point.set(event_node.prev.unwrap());
                    }
                }
            }
        });
    }
}

pub trait OpaqueEventDropper {}

impl <T, E> OpaqueEventDropper for Box<PromiseNode<T, E>> {}

impl OpaqueEventDropper for EventDropper {}

pub struct BoolEvent {
    fired: ::std::rc::Rc<::std::cell::Cell<bool>>,
}

impl BoolEvent {
    pub fn new(fired: ::std::rc::Rc<::std::cell::Cell<bool>>) -> BoolEvent {
        BoolEvent { fired: fired }
    }
}

impl Event for BoolEvent {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        self.fired.set(true);
        None
    }
}

pub enum OnReadyEvent {
    Empty,
    AlreadyReady,
    Full(EventHandle),
}

impl OnReadyEvent {
    fn is_already_ready(&self) -> bool {
        match self {
            &OnReadyEvent::AlreadyReady => true,
            _ => false,
        }
    }

    fn is_empty(&self) -> bool {
        match self {
            &OnReadyEvent::Empty => true,
            _ => false,
        }
    }

    fn init(&mut self, new_event: EventHandle) {
        if self.is_already_ready() {
            new_event.arm_breadth_first();
        } else {
            *self = OnReadyEvent::Full(new_event);
        }
    }

    fn arm(&mut self) {
        if self.is_empty() {
            *self = OnReadyEvent::AlreadyReady;
        } else {
            let old_self = ::std::mem::replace(self, OnReadyEvent::Empty);
            match old_self {
                OnReadyEvent::Full(event) => {
                    event.arm_depth_first();
                }
                _ => {
                    panic!("armed an event twice?");
                }
            }
        }
    }
}

pub struct PromiseAndFulfillerHub<T, E> where T: 'static, E: 'static {
    result: Option<Result<T, E>>,
    on_ready_event: OnReadyEvent,
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn new() -> PromiseAndFulfillerHub<T, E> {
        PromiseAndFulfillerHub { result: None::<Result<T, E>>, on_ready_event: OnReadyEvent::Empty }
    }
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn fulfill(&mut self, value: T) {
        if self.result.is_none() {
            self.result = Some(Ok(value));
            self.on_ready_event.arm();
        }
    }

    pub fn reject(&mut self, error: E) {
        if self.result.is_none() {
            self.result = Some(Err(error));
            self.on_ready_event.arm();
        }
    }
}

pub struct PromiseAndFulfillerWrapper<T, E> where T: 'static, E: 'static {
    hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>
}

impl <T, E> PromiseAndFulfillerWrapper<T, E> {
    pub fn new(hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>)
               -> PromiseAndFulfillerWrapper<T, E>
    {
        PromiseAndFulfillerWrapper { hub: hub }
    }
}

impl <T, E> Drop for PromiseAndFulfillerWrapper<T, E> {
    fn drop(&mut self) {
        self.hub.borrow_mut().on_ready_event = OnReadyEvent::Empty;
    }
}

impl <T, E> PromiseNode<T, E> for PromiseAndFulfillerWrapper<T, E> {
    fn on_ready(&mut self, event: EventHandle) {
        self.hub.borrow_mut().on_ready_event.init(event);
    }
    fn get(self: Box<Self>) -> Result<T, E> {
        match ::std::mem::replace(&mut self.hub.borrow_mut().result, None) {
            None => panic!("no result!"),
            Some(r) => r
        }
    }
}

pub struct TaskSetImpl<T, E> where T: 'static, E: 'static {
    reaper: Rc<RefCell<Box<TaskReaper<T, E>>>>,
    tasks: Rc<RefCell<HashMap<EventHandle, EventDropper>>>,
}

impl <T, E> TaskSetImpl <T, E> {
    pub fn new(reaper: Box<TaskReaper<T, E>>) -> TaskSetImpl<T, E> {
        TaskSetImpl {
            reaper: Rc::new(RefCell::new(reaper)),
            tasks: Rc::new(RefCell::new(HashMap::new())),
        }
    }

      pub fn add(&self, mut node: Box<PromiseNode<T, E>>) {
          let (handle, dropper) = EventHandle::new();
          node.on_ready(handle);
          let task = Task {
              weak_reaper: Rc::downgrade(&self.reaper),
              weak_tasks: Rc::downgrade(&self.tasks),
              node: Some(node),
              event_handle: handle
          };
          handle.set(Box::new(task));
          self.tasks.borrow_mut().insert(handle, dropper);
    }
}

pub struct Task<T, E> where T: 'static, E: 'static {
    weak_reaper: Weak<RefCell<Box<TaskReaper<T, E>>>>,
    weak_tasks: Weak<RefCell<HashMap<EventHandle, EventDropper>>>,
    node: Option<Box<PromiseNode<T, E>>>,
    event_handle: EventHandle,
}

impl <T, E> Event for Task<T, E> {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        let maybe_node = ::std::mem::replace(&mut self.node, None);
        match maybe_node {
            None => {
                unreachable!()
            }
            Some(node) => {
                match self.weak_reaper.upgrade() {
                    None => (),
                    Some(reaper) => {
                        match node.get() {
                            Ok(v) => {
                                reaper.borrow_mut().task_succeeded(v);
                            }
                            Err(e) => {
                                reaper.borrow_mut().task_failed(e);
                            }
                        }
                    }
                }
            }
        }
        let tasks = self.weak_tasks.upgrade().expect("dangling reference to tasks?");
        let mut tmp = tasks.borrow_mut();
        match tmp.remove(&self.event_handle) {
            None => None,
            Some(v) => Some(Box::new(v)),
        }
    }
}
<commit_msg>Handle the case when the tail event is dropped.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cell::RefCell;
use std::rc::{Rc, Weak};
use std::collections::HashMap;
use std::result::Result;
use handle_table::{Handle};
use {EventLoop, TaskReaper};

pub mod promise_node;

thread_local!(pub static EVENT_LOOP: RefCell<Option<EventLoop>> = RefCell::new(None));

pub fn with_current_event_loop<F, R>(f: F) -> R
    where F: FnOnce(&EventLoop) -> R
{
    EVENT_LOOP.with(|maybe_event_loop| {
        match &*maybe_event_loop.borrow() {
            &None => panic!("current thread has no event loop"),
            &Some(ref event_loop) => f(event_loop),
        }
    })
}

pub trait PromiseNode<T, E> {
    /// Arms the given event when the promised value is ready.
    fn on_ready(&mut self, event: EventHandle);

    /// Tells the node that `_self_ptr` is the pointer that owns this node, and will continue to own
    /// this node until it is destroyed or set_self_pointer() is called again. promise_node::Chain uses
    /// this to shorten redundant chains.  The default implementation does nothing; only
    /// promise_node::Chain should implement this.
    fn set_self_pointer(&mut self, _self_ptr: Weak<RefCell<promise_node::ChainState<T, E>>>) {}
    fn get(self: Box<Self>) -> Result<T, E>;
}

pub trait Event {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>>;
}

#[derive(PartialEq, Eq, Copy, Clone, Hash)]
pub struct EventHandle(pub Handle);

impl EventHandle {
    pub fn new() -> (EventHandle, EventDropper) {
        with_current_event_loop(|event_loop| {
            let node = EventNode { event: None, next: None, prev: None };
            let handle = EventHandle(event_loop.events.borrow_mut().push(node));
            (handle, EventDropper { event_handle: handle })
        })
    }

    pub fn set(&self, event: Box<Event>) {
        with_current_event_loop(|event_loop| {
            event_loop.events.borrow_mut()[self.0].event = Some(event);
        })
    }

    pub fn arm_breadth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_breadth_first(self);
        });
    }

    pub fn arm_depth_first(self) {
        with_current_event_loop(|event_loop| {
            event_loop.arm_depth_first(self);
        });
    }
}

pub struct EventNode {
    pub event: Option<Box<Event>>,
    pub next: Option<EventHandle>,
    pub prev: Option<EventHandle>
}

#[derive(PartialEq, Eq, Hash)]
pub struct EventDropper {
    event_handle: EventHandle,
}

impl Drop for EventDropper {
    fn drop(&mut self) {
        with_current_event_loop(|event_loop| {
            match event_loop.currently_firing.get() {
                Some(h) if h == self.event_handle => panic!("Promise callback destroyed itself."),
                _ => (),
            }
            let maybe_event_node = event_loop.events.borrow_mut().remove(self.event_handle.0);

            match maybe_event_node {
                None => {}
                Some(event_node) => {

                    // event_node.next.prev = event_node.prev
                    match event_node.next {
                        Some(e) => {
                            event_loop.events.borrow_mut()[e.0].prev = event_node.prev;
                        }
                        None => {}
                    }
                    // event_node.prev.next = event_node.next
                    match event_node.prev {
                        Some(e) => {
                            event_loop.events.borrow_mut()[e.0].next = event_node.next;
                        }
                        None => {}
                    }

                    let insertion_point = event_loop.depth_first_insertion_point.get();
                    if insertion_point.0 == self.event_handle.0 {
                        event_loop.depth_first_insertion_point.set(event_node.prev.unwrap());
                    }

                    let tail = event_loop.tail.get();
                    if tail.0 == self.event_handle.0 {
                        event_loop.tail.set(event_node.prev.unwrap());
                    }
                }
            }
        });
    }
}

pub trait OpaqueEventDropper {}

impl <T, E> OpaqueEventDropper for Box<PromiseNode<T, E>> {}

impl OpaqueEventDropper for EventDropper {}

pub struct BoolEvent {
    fired: ::std::rc::Rc<::std::cell::Cell<bool>>,
}

impl BoolEvent {
    pub fn new(fired: ::std::rc::Rc<::std::cell::Cell<bool>>) -> BoolEvent {
        BoolEvent { fired: fired }
    }
}

impl Event for BoolEvent {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        self.fired.set(true);
        None
    }
}

pub enum OnReadyEvent {
    Empty,
    AlreadyReady,
    Full(EventHandle),
}

impl OnReadyEvent {
    fn is_already_ready(&self) -> bool {
        match self {
            &OnReadyEvent::AlreadyReady => true,
            _ => false,
        }
    }

    fn is_empty(&self) -> bool {
        match self {
            &OnReadyEvent::Empty => true,
            _ => false,
        }
    }

    fn init(&mut self, new_event: EventHandle) {
        if self.is_already_ready() {
            new_event.arm_breadth_first();
        } else {
            *self = OnReadyEvent::Full(new_event);
        }
    }

    fn arm(&mut self) {
        if self.is_empty() {
            *self = OnReadyEvent::AlreadyReady;
        } else {
            let old_self = ::std::mem::replace(self, OnReadyEvent::Empty);
            match old_self {
                OnReadyEvent::Full(event) => {
                    event.arm_depth_first();
                }
                _ => {
                    panic!("armed an event twice?");
                }
            }
        }
    }
}

pub struct PromiseAndFulfillerHub<T, E> where T: 'static, E: 'static {
    result: Option<Result<T, E>>,
    on_ready_event: OnReadyEvent,
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn new() -> PromiseAndFulfillerHub<T, E> {
        PromiseAndFulfillerHub { result: None::<Result<T, E>>, on_ready_event: OnReadyEvent::Empty }
    }
}

impl <T, E> PromiseAndFulfillerHub<T, E> {
    pub fn fulfill(&mut self, value: T) {
        if self.result.is_none() {
            self.result = Some(Ok(value));
            self.on_ready_event.arm();
        }
    }

    pub fn reject(&mut self, error: E) {
        if self.result.is_none() {
            self.result = Some(Err(error));
            self.on_ready_event.arm();
        }
    }
}

pub struct PromiseAndFulfillerWrapper<T, E> where T: 'static, E: 'static {
    hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>
}

impl <T, E> PromiseAndFulfillerWrapper<T, E> {
    pub fn new(hub: ::std::rc::Rc<::std::cell::RefCell<PromiseAndFulfillerHub<T, E>>>)
               -> PromiseAndFulfillerWrapper<T, E>
    {
        PromiseAndFulfillerWrapper { hub: hub }
    }
}

impl <T, E> Drop for PromiseAndFulfillerWrapper<T, E> {
    fn drop(&mut self) {
        self.hub.borrow_mut().on_ready_event = OnReadyEvent::Empty;
    }
}

impl <T, E> PromiseNode<T, E> for PromiseAndFulfillerWrapper<T, E> {
    fn on_ready(&mut self, event: EventHandle) {
        self.hub.borrow_mut().on_ready_event.init(event);
    }
    fn get(self: Box<Self>) -> Result<T, E> {
        match ::std::mem::replace(&mut self.hub.borrow_mut().result, None) {
            None => panic!("no result!"),
            Some(r) => r
        }
    }
}

pub struct TaskSetImpl<T, E> where T: 'static, E: 'static {
    reaper: Rc<RefCell<Box<TaskReaper<T, E>>>>,
    tasks: Rc<RefCell<HashMap<EventHandle, EventDropper>>>,
}

impl <T, E> TaskSetImpl <T, E> {
    pub fn new(reaper: Box<TaskReaper<T, E>>) -> TaskSetImpl<T, E> {
        TaskSetImpl {
            reaper: Rc::new(RefCell::new(reaper)),
            tasks: Rc::new(RefCell::new(HashMap::new())),
        }
    }

      pub fn add(&self, mut node: Box<PromiseNode<T, E>>) {
          let (handle, dropper) = EventHandle::new();
          node.on_ready(handle);
          let task = Task {
              weak_reaper: Rc::downgrade(&self.reaper),
              weak_tasks: Rc::downgrade(&self.tasks),
              node: Some(node),
              event_handle: handle
          };
          handle.set(Box::new(task));
          self.tasks.borrow_mut().insert(handle, dropper);
    }
}

pub struct Task<T, E> where T: 'static, E: 'static {
    weak_reaper: Weak<RefCell<Box<TaskReaper<T, E>>>>,
    weak_tasks: Weak<RefCell<HashMap<EventHandle, EventDropper>>>,
    node: Option<Box<PromiseNode<T, E>>>,
    event_handle: EventHandle,
}

impl <T, E> Event for Task<T, E> {
    fn fire(&mut self) -> Option<Box<OpaqueEventDropper>> {
        let maybe_node = ::std::mem::replace(&mut self.node, None);
        match maybe_node {
            None => {
                unreachable!()
            }
            Some(node) => {
                match self.weak_reaper.upgrade() {
                    None => (),
                    Some(reaper) => {
                        match node.get() {
                            Ok(v) => {
                                reaper.borrow_mut().task_succeeded(v);
                            }
                            Err(e) => {
                                reaper.borrow_mut().task_failed(e);
                            }
                        }
                    }
                }
            }
        }
        let tasks = self.weak_tasks.upgrade().expect("dangling reference to tasks?");
        let mut tmp = tasks.borrow_mut();
        match tmp.remove(&self.event_handle) {
            None => None,
            Some(v) => Some(Box::new(v)),
        }
    }
}
<|endoftext|>