<commit_before>extern crate flate;

use std::str;
use std::io::File;
use flate::inflate_bytes_zlib;
use commit::Commit;
use serialization::Serializable;
use object_type;
use object_header::ObjectHeader;
use object_id::ObjectId;
use meta::Meta;

#[test]
fn decode_commit() {
    // Test.
    /*let path = "C:/Projects/RustGit/.git/objects/37/eaf372e4a1a5638706b757f8a086b78a5b490b";
    let compressed_contents = File::open(&Path::new(path)).read_to_end().unwrap();
    let contents = inflate_bytes_zlib(compressed_contents.as_slice()).unwrap();
    let s = str::from_utf8(contents.as_slice()).unwrap();*/
    //let bytes = File::open(&Path::new(".gitignore")).read_to_string().unwrap();
    let c = Commit {
        meta: Meta {
            id: ObjectId::new("blabla"),
            header: ObjectHeader {
                typ: object_type::Commit,
                length: 1
            },
        },
        author_name: "Kai Sellgren",
        author_email: "kaisellgren@gmail.com",
        author_date: 0,
        committer_name: "Kai Sellgren 2",
        committer_email: "kaisellgren+2@gmail.com",
        commit_date: 2,
        message: "Hooray!",
        tree_id: ObjectId::new("test"),
        parent_ids: vec![ObjectId::new("first"), ObjectId::new("second")]
    };

    println!("{}", str::from_utf8(c.encode().as_slice()).unwrap());
    fail!("asd");
}
<commit_msg>Update commit unit tests<commit_after>extern crate flate;

use std::str;
use std::io::File;
use flate::inflate_bytes_zlib;
use commit::Commit;
use commit;
use serialization::Serializable;
use object_type;
use object_header::ObjectHeader;
use object_id::ObjectId;
use meta::Meta;
use std::io::fs;
use std::num::FromStrRadix;
use conversion;

#[test]
fn decode_commit() {
    // Test.
    /*let path = "C:/Projects/RustGit/.git/objects/37/eaf372e4a1a5638706b757f8a086b78a5b490b";
    let compressed_contents = File::open(&Path::new(path)).read_to_end().unwrap();
    let contents = inflate_bytes_zlib(compressed_contents.as_slice()).unwrap();
    let s = str::from_utf8(contents.as_slice()).unwrap();*/
    //let bytes = File::open(&Path::new(".gitignore")).read_to_string().unwrap();
    let c = Commit {
fn create_test_commit() -> Commit {
    Commit {
        meta: Meta {
            id: ObjectId::from_string("b744d5cddb5095249299d95ee531cbd990741140"),
            header: ObjectHeader {
                typ: object_type::Commit,
                length: 0
            },
        },
        author_name: "Kai".into_string(),
        author_email: "kaisellgren@gmail.com".into_string(),
        author_date: 1388624645,
        committer_name: "Kai 2".into_string(),
        committer_email: "kaisellgren+foo@gmail.com".into_string(),
        commit_date: 1388624646,
        message: "foo bar baz qux".into_string(),
        tree_id: ObjectId::from_string("b744d5cddb5095249299d95ee531cbd990741140"),
        parent_ids: vec![ObjectId::from_string("b744d5cddb5095249299d95ee531cbd990741141"), ObjectId::from_string("b744d5cddb5095249299d95ee531cbd990741142")]
    }
}

#[test]
fn encode_commit() {
    /*let path = "C:/Projects/RustGit/.git/objects/37/eaf372e4a1a5638706b757f8a086b78a5b490b";
    let compressed_contents = File::open(&Path::new(path)).read_to_end().unwrap();
    let contents = inflate_bytes_zlib(compressed_contents.as_slice()).unwrap();
    let s = str::from_utf8(contents.as_slice()).unwrap();
    println!("{}", s);*/

    //let bytes = File::open(&Path::new(".gitignore")).read_to_string().unwrap();

    let expected = File::open(&Path::new("resources/tests/commit")).read_to_end().unwrap();
    let encoded = create_test_commit().encode();

    assert_eq!(expected, encoded);
}

#[test]
fn decode_commit() {
    let commit = create_test_commit();

    let contents = File::open(&Path::new("resources/tests/commit")).read_to_end().unwrap();
    let decoded = commit::decode(contents.as_slice()).unwrap();

    assert_eq!(commit, decoded);

    fail!("STOP");
}<|endoftext|>


<commit_before>use byteorder::{ByteOrder, NativeEndian, ReadBytesExt, WriteBytesExt};
use std::collections::{btree_map, BTreeMap, HashMap};
use std::collections::Bound::{Included, Excluded};
use std::mem;
use std::ptr;

use error::{EvalError, EvalResult};
use primval::PrimVal;

pub struct Memory {
    alloc_map: HashMap<u64, Allocation>,
    next_id: u64,
    pub pointer_size: usize,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AllocId(u64);

#[derive(Debug)]
pub struct Allocation {
    pub bytes: Box<[u8]>,
    pub relocations: BTreeMap<usize, AllocId>,
    // TODO(tsion): undef mask
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Pointer {
    pub alloc_id: AllocId,
    pub offset: usize,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FieldRepr {
    pub offset: usize,
    pub size: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Repr {
    /// Representation for a non-aggregate type such as a boolean, integer, character or pointer.
    Primitive {
        size: usize
    },

    /// The representation for aggregate types including structs, enums, and tuples.
    Aggregate {
        /// The size of the discriminant (an integer). Should be between 0 and 8. Always 0 for
        /// structs and tuples.
        discr_size: usize,

        /// The size of the entire aggregate, including the discriminant.
        size: usize,

        /// The representations of the contents of each variant.
        variants: Vec<Vec<FieldRepr>>,
    },

    Array {
        elem_size: usize,

        /// Number of elements.
        length: usize,
    },
}

impl Memory {
    pub fn new() -> Self {
        Memory {
            alloc_map: HashMap::new(),
            next_id: 0,

            // TODO(tsion): Should this be host's or target's usize?
            pointer_size: mem::size_of::<usize>(),
        }
    }

    pub fn allocate(&mut self, size: usize) -> Pointer {
        let id = AllocId(self.next_id);
        let alloc = Allocation {
            bytes: vec![0; size].into_boxed_slice(),
            relocations: BTreeMap::new(),
        };
        self.alloc_map.insert(self.next_id, alloc);
        self.next_id += 1;
        Pointer {
            alloc_id: id,
            offset: 0,
        }
    }

    pub fn get(&self, id: AllocId) -> EvalResult<&Allocation> {
        self.alloc_map.get(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    pub fn get_mut(&mut self, id: AllocId) -> EvalResult<&mut Allocation> {
        self.alloc_map.get_mut(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        try!(self.check_readable_bytes(ptr, size));
        try!(self.get(ptr.alloc_id)).checked_slice(ptr.offset, size)
    }

    fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        try!(self.clear_relocations(ptr, size));
        try!(self.get_mut(ptr.alloc_id)).checked_slice_mut(ptr.offset, size)
    }

    fn check_readable_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
        if try!(self.relocations(ptr, size)).count() == 0 {
            // TODO(tsion): Track and check for undef bytes.
            Ok(())
        } else {
            Err(EvalError::ReadPointerAsBytes)
        }
    }

    fn relocations(&self, ptr: Pointer, size: usize)
        -> EvalResult<btree_map::Range<usize, AllocId>>
    {
        let start = ptr.offset.saturating_sub(self.pointer_size - 1);
        let end = ptr.offset + size;
        let alloc = try!(self.get(ptr.alloc_id));
        Ok(alloc.relocations.range(Included(&start), Excluded(&end)))
    }

    fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let overlapping_start = try!(self.relocations(ptr, 0)).count();
        let overlapping_end = try!(self.relocations(ptr.offset(size as isize), 0)).count();
        if overlapping_start + overlapping_end == 0 {
            Ok(())
        } else {
            Err(EvalError::ReadPointerAsBytes)
        }
    }

    fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let keys: Vec<_> = try!(self.relocations(ptr, size)).map(|(&k, _)| k).collect();
        let alloc = try!(self.get_mut(ptr.alloc_id));
        for k in keys {
            alloc.relocations.remove(&k);
        }
        Ok(())
    }

    fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        let relocations: Vec<_> = try!(self.get_mut(src.alloc_id)).relocations
            .range(Included(&src.offset), Excluded(&(src.offset + size)))
            .map(|(&offset, &alloc_id)| {
                // Update relocation offsets for the new positions in the destination allocation.
                (offset + dest.offset - src.offset, alloc_id)
            }).collect();
        try!(self.get_mut(dest.alloc_id)).relocations.extend(relocations);
        Ok(())
    }

    pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        // TODO(tsion): Track and check for undef bytes.
        try!(self.check_relocation_edges(src, size));

        let src_bytes = {
            let alloc = try!(self.get(src.alloc_id));
            try!(alloc.checked_slice(src.offset, size)).as_ptr()
        };
        let dest_bytes = try!(self.get_bytes_mut(dest, size)).as_mut_ptr();

        // SAFE: The above indexing would have panicked if there weren't at least `size` bytes
        // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
        // `dest` could possibly overlap.
        unsafe {
            if src.alloc_id == dest.alloc_id {
                ptr::copy(src_bytes, dest_bytes, size);
            } else {
                ptr::copy_nonoverlapping(src_bytes, dest_bytes, size);
            }
        }

        self.copy_relocations(src, dest, size)
    }

    pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<()> {
        self.get_bytes_mut(ptr, src.len()).map(|dest| dest.clone_from_slice(src))
    }

    pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<Pointer> {
        let alloc = try!(self.get(ptr.alloc_id));
        let mut bytes = try!(alloc.checked_slice(ptr.offset, self.pointer_size));
        let offset = bytes.read_uint::<NativeEndian>(self.pointer_size).unwrap() as usize;

        match alloc.relocations.get(&ptr.offset) {
            Some(&alloc_id) => Ok(Pointer { alloc_id: alloc_id, offset: offset }),
            None => Err(EvalError::ReadBytesAsPointer),
        }
    }

    pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<()> {
        {
            let size = self.pointer_size;
            let mut bytes = try!(self.get_bytes_mut(dest, size));
            bytes.write_uint::<NativeEndian>(ptr.offset as u64, size).unwrap();
        }
        try!(self.get_mut(dest.alloc_id)).relocations.insert(dest.offset, ptr.alloc_id);
        Ok(())
    }

    pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> {
        let pointer_size = self.pointer_size;
        match val {
            PrimVal::Bool(b) => self.write_bool(ptr, b),
            PrimVal::I8(n)   => self.write_int(ptr, n as i64, 1),
            PrimVal::I16(n)  => self.write_int(ptr, n as i64, 2),
            PrimVal::I32(n)  => self.write_int(ptr, n as i64, 4),
            PrimVal::I64(n)  => self.write_int(ptr, n as i64, 8),
            PrimVal::U8(n)   => self.write_uint(ptr, n as u64, 1),
            PrimVal::U16(n)  => self.write_uint(ptr, n as u64, 2),
            PrimVal::U32(n)  => self.write_uint(ptr, n as u64, 4),
            PrimVal::U64(n)  => self.write_uint(ptr, n as u64, 8),
            PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
            PrimVal::AbstractPtr(_p) => unimplemented!(),
        }
    }

    pub fn read_bool(&self, ptr: Pointer) -> EvalResult<bool> {
        let bytes = try!(self.get_bytes(ptr, 1));
        match bytes[0] {
            0 => Ok(false),
            1 => Ok(true),
            _ => Err(EvalError::InvalidBool),
        }
    }

    pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<()> {
        self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8)
    }

    pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<i64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_int::<NativeEndian>(size).unwrap())
    }

    pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_int::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<u64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_uint::<NativeEndian>(size).unwrap())
    }

    pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_uint::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_isize(&self, ptr: Pointer) -> EvalResult<i64> {
        self.read_int(ptr, self.pointer_size)
    }

    pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_int(ptr, n, size)
    }

    pub fn read_usize(&self, ptr: Pointer) -> EvalResult<u64> {
        self.read_uint(ptr, self.pointer_size)
    }

    pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_uint(ptr, n, size)
    }
}

impl Allocation {
    fn checked_slice(&self, offset: usize, size: usize) -> EvalResult<&[u8]> {
        let start = offset;
        let end = start + size;
        if start <= self.bytes.len() && end <= self.bytes.len() {
            Ok(&self.bytes[start..end])
        } else {
            Err(EvalError::PointerOutOfBounds)
        }
    }

    fn checked_slice_mut(&mut self, offset: usize, size: usize) -> EvalResult<&mut [u8]> {
        let start = offset;
        let end = start + size;
        if start <= self.bytes.len() && end <= self.bytes.len() {
            Ok(&mut self.bytes[start..end])
        } else {
            Err(EvalError::PointerOutOfBounds)
        }
    }
}

impl Pointer {
    pub fn offset(self, i: isize) -> Self {
        Pointer { offset: (self.offset as isize + i) as usize, ..self }
    }
}

impl Repr {
    pub fn size(&self) -> usize {
        match *self {
            Repr::Primitive { size } => size,
            Repr::Aggregate { size, .. } => size,
            Repr::Array { elem_size, length } => elem_size * length,
        }
    }
}
<commit_msg>Refactor memory/allocation handling.<commit_after>use byteorder::{ByteOrder, NativeEndian, ReadBytesExt, WriteBytesExt};
use std::collections::{btree_map, BTreeMap, HashMap};
use std::collections::Bound::{Included, Excluded};
use std::mem;
use std::ptr;

use error::{EvalError, EvalResult};
use primval::PrimVal;

pub struct Memory {
    alloc_map: HashMap<u64, Allocation>,
    next_id: u64,
    pub pointer_size: usize,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AllocId(u64);

#[derive(Debug)]
pub struct Allocation {
    pub bytes: Box<[u8]>,
    pub relocations: BTreeMap<usize, AllocId>,
    // TODO(tsion): undef mask
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Pointer {
    pub alloc_id: AllocId,
    pub offset: usize,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct FieldRepr {
    pub offset: usize,
    pub size: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Repr {
    /// Representation for a non-aggregate type such as a boolean, integer, character or pointer.
    Primitive {
        size: usize
    },

    /// The representation for aggregate types including structs, enums, and tuples.
    Aggregate {
        /// The size of the discriminant (an integer). Should be between 0 and 8. Always 0 for
        /// structs and tuples.
        discr_size: usize,

        /// The size of the entire aggregate, including the discriminant.
        size: usize,

        /// The representations of the contents of each variant.
        variants: Vec<Vec<FieldRepr>>,
    },

    Array {
        elem_size: usize,

        /// Number of elements.
        length: usize,
    },
}

impl Memory {
    pub fn new() -> Self {
        Memory {
            alloc_map: HashMap::new(),
            next_id: 0,

            // TODO(tsion): Should this be host's or target's usize?
            pointer_size: mem::size_of::<usize>(),
        }
    }

    pub fn allocate(&mut self, size: usize) -> Pointer {
        let id = AllocId(self.next_id);
        let alloc = Allocation {
            bytes: vec![0; size].into_boxed_slice(),
            relocations: BTreeMap::new(),
        };
        self.alloc_map.insert(self.next_id, alloc);
        self.next_id += 1;
        Pointer {
            alloc_id: id,
            offset: 0,
        }
    }

    pub fn get(&self, id: AllocId) -> EvalResult<&Allocation> {
        self.alloc_map.get(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    pub fn get_mut(&mut self, id: AllocId) -> EvalResult<&mut Allocation> {
        self.alloc_map.get_mut(&id.0).ok_or(EvalError::DanglingPointerDeref)
    }

    fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        let alloc = try!(self.get(ptr.alloc_id));
        if ptr.offset + size > alloc.bytes.len() {
            return Err(EvalError::PointerOutOfBounds);
        }
        Ok(&alloc.bytes[ptr.offset..ptr.offset + size])
    }

    fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        let alloc = try!(self.get_mut(ptr.alloc_id));
        if ptr.offset + size > alloc.bytes.len() {
            return Err(EvalError::PointerOutOfBounds);
        }
        Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
    }

    fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
        if try!(self.relocations(ptr, size)).count() != 0 {
            return Err(EvalError::ReadPointerAsBytes);
        }
        // TODO(tsion): Track and check for undef bytes.
        self.get_bytes_unchecked(ptr, size)
    }

    fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
        try!(self.clear_relocations(ptr, size));
        self.get_bytes_unchecked_mut(ptr, size)
    }

    fn relocations(&self, ptr: Pointer, size: usize)
        -> EvalResult<btree_map::Range<usize, AllocId>>
    {
        let start = ptr.offset.saturating_sub(self.pointer_size - 1);
        let end = start + size;
        Ok(try!(self.get(ptr.alloc_id)).relocations.range(Included(&start), Excluded(&end)))
    }

    fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let keys: Vec<_> = try!(self.relocations(ptr, size)).map(|(&k, _)| k).collect();
        let alloc = try!(self.get_mut(ptr.alloc_id));
        for k in keys {
            alloc.relocations.remove(&k);
        }
        Ok(())
    }

    fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
        let overlapping_start = try!(self.relocations(ptr, 0)).count();
        let overlapping_end = try!(self.relocations(ptr.offset(size as isize), 0)).count();
        if overlapping_start + overlapping_end != 0 {
            return Err(EvalError::ReadPointerAsBytes);
        }
        Ok(())
    }

    fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        let relocations: Vec<_> = try!(self.relocations(src, size))
            .map(|(&offset, &alloc_id)| {
                // Update relocation offsets for the new positions in the destination allocation.
                (offset + dest.offset - src.offset, alloc_id)
            })
            .collect();
        try!(self.get_mut(dest.alloc_id)).relocations.extend(relocations);
        Ok(())
    }

    pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
        // TODO(tsion): Track and check for undef bytes.
        try!(self.check_relocation_edges(src, size));

        let src_bytes = try!(self.get_bytes_unchecked_mut(src, size)).as_mut_ptr();
        let dest_bytes = try!(self.get_bytes_mut(dest, size)).as_mut_ptr();

        // SAFE: The above indexing would have panicked if there weren't at least `size` bytes
        // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
        // `dest` could possibly overlap.
        unsafe {
            if src.alloc_id == dest.alloc_id {
                ptr::copy(src_bytes, dest_bytes, size);
            } else {
                ptr::copy_nonoverlapping(src_bytes, dest_bytes, size);
            }
        }

        self.copy_relocations(src, dest, size)
    }

    pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<()> {
        self.get_bytes_mut(ptr, src.len()).map(|dest| dest.clone_from_slice(src))
    }

    pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<Pointer> {
        let size = self.pointer_size;
        let offset = try!(self.get_bytes_unchecked(ptr, size))
            .read_uint::<NativeEndian>(size).unwrap() as usize;
        let alloc = try!(self.get(ptr.alloc_id));
        match alloc.relocations.get(&ptr.offset) {
            Some(&alloc_id) => Ok(Pointer { alloc_id: alloc_id, offset: offset }),
            None => Err(EvalError::ReadBytesAsPointer),
        }
    }

    pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<()> {
        {
            let size = self.pointer_size;
            let mut bytes = try!(self.get_bytes_mut(dest, size));
            bytes.write_uint::<NativeEndian>(ptr.offset as u64, size).unwrap();
        }
        try!(self.get_mut(dest.alloc_id)).relocations.insert(dest.offset, ptr.alloc_id);
        Ok(())
    }

    pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> {
        let pointer_size = self.pointer_size;
        match val {
            PrimVal::Bool(b) => self.write_bool(ptr, b),
            PrimVal::I8(n)   => self.write_int(ptr, n as i64, 1),
            PrimVal::I16(n)  => self.write_int(ptr, n as i64, 2),
            PrimVal::I32(n)  => self.write_int(ptr, n as i64, 4),
            PrimVal::I64(n)  => self.write_int(ptr, n as i64, 8),
            PrimVal::U8(n)   => self.write_uint(ptr, n as u64, 1),
            PrimVal::U16(n)  => self.write_uint(ptr, n as u64, 2),
            PrimVal::U32(n)  => self.write_uint(ptr, n as u64, 4),
            PrimVal::U64(n)  => self.write_uint(ptr, n as u64, 8),
            PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size),
            PrimVal::AbstractPtr(_p) => unimplemented!(),
        }
    }

    pub fn read_bool(&self, ptr: Pointer) -> EvalResult<bool> {
        let bytes = try!(self.get_bytes(ptr, 1));
        match bytes[0] {
            0 => Ok(false),
            1 => Ok(true),
            _ => Err(EvalError::InvalidBool),
        }
    }

    pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<()> {
        self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8)
    }

    pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<i64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_int::<NativeEndian>(size).unwrap())
    }

    pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_int::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<u64> {
        self.get_bytes(ptr, size).map(|mut b| b.read_uint::<NativeEndian>(size).unwrap())
    }

    pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<()> {
        self.get_bytes_mut(ptr, size).map(|mut b| b.write_uint::<NativeEndian>(n, size).unwrap())
    }

    pub fn read_isize(&self, ptr: Pointer) -> EvalResult<i64> {
        self.read_int(ptr, self.pointer_size)
    }

    pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_int(ptr, n, size)
    }

    pub fn read_usize(&self, ptr: Pointer) -> EvalResult<u64> {
        self.read_uint(ptr, self.pointer_size)
    }

    pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> {
        let size = self.pointer_size;
        self.write_uint(ptr, n, size)
    }
}

impl Pointer {
    pub fn offset(self, i: isize) -> Self {
        Pointer { offset: (self.offset as isize + i) as usize, ..self }
    }
}

impl Repr {
    pub fn size(&self) -> usize {
        match *self {
            Repr::Primitive { size } => size,
            Repr::Aggregate { size, .. } => size,
            Repr::Array { elem_size, length } => elem_size * length,
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jordi Boggiano <j.boggiano@seld.be>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

/* last synced with: env (GNU coreutils) 8.13 */

// spell-checker:ignore (ToDO) chdir execvp progname subcommand subcommands unsets

#[macro_use]
extern crate clap;

#[macro_use]
extern crate uucore;

use clap::{App, AppSettings, Arg};
use ini::Ini;
use std::borrow::Cow;
use std::env;
use std::io::{self, Write};
use std::iter::Iterator;
use std::process::Command;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};

const USAGE: &str = "env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]";
const AFTER_HELP: &str = "\
A mere - implies -i. If no COMMAND, print the resulting environment.
";

struct Options<'a> {
    ignore_env: bool,
    null: bool,
    running_directory: Option<&'a str>,
    files: Vec<&'a str>,
    unsets: Vec<&'a str>,
    sets: Vec<(&'a str, &'a str)>,
    program: Vec<&'a str>,
}

// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
fn print_env(null: bool) {
    let stdout_raw = io::stdout();
    let mut stdout = stdout_raw.lock();
    for (n, v) in env::vars() {
        write!(stdout, "{}={}{}", n, v, if null { '\0' } else { '\n' }).unwrap();
    }
}

fn parse_name_value_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<bool, i32> {
    // is it a NAME=VALUE like opt ?
    if let Some(idx) = opt.find('=') {
        // yes, so push name, value pair
        let (name, value) = opt.split_at(idx);
        opts.sets.push((name, &value['='.len_utf8()..]));

        Ok(false)
    } else {
        // no, it's a program-like opt
        parse_program_opt(opts, opt).map(|_| true)
    }
}

fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<(), i32> {
    if opts.null {
        eprintln!(
            "{}: cannot specify --null (-0) with command",
            uucore::util_name()
        );
        eprintln!(
            "Type \"{} --help\" for detailed information",
            uucore::execution_phrase()
        );
        Err(1)
    } else {
        opts.program.push(opt);
        Ok(())
    }
}

fn load_config_file(opts: &mut Options) -> UResult<()> {
    // NOTE: config files are parsed using an INI parser b/c it's available and compatible with ".env"-style files
    //   ... * but support for actual INI files, although working, is not intended, nor claimed
    for &file in &opts.files {
        let conf = if file == "-" {
            let stdin = io::stdin();
            let mut stdin_locked = stdin.lock();
            Ini::read_from(&mut stdin_locked)
        } else {
            Ini::load_from_file(file)
        };

        let conf = conf.map_err(|error| {
            show_error!("{}: {}", file.maybe_quote(), error);
            1
        })?;

        for (_, prop) in &conf {
            // ignore all INI section lines (treat them as comments)
            for (key, value) in prop.iter() {
                env::set_var(key, value);
            }
        }
    }

    Ok(())
}

#[cfg(not(windows))]
fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
    let progname = Cow::from(args[0]);
    (progname, &args[1..])
}

#[cfg(windows)]
fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
    args.insert(0, "/d/c");
    let progname = env::var("ComSpec")
        .map(Cow::from)
        .unwrap_or_else(|_| Cow::from("cmd"));

    (progname, &args[..])
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .usage(USAGE)
        .after_help(AFTER_HELP)
        .setting(AppSettings::AllowExternalSubcommands)
        .arg(Arg::with_name("ignore-environment")
            .short("i")
            .long("ignore-environment")
            .help("start with an empty environment"))
        .arg(Arg::with_name("chdir")
            .short("c")
            .long("chdir")
            .takes_value(true)
            .number_of_values(1)
            .value_name("DIR")
            .help("change working directory to DIR"))
        .arg(Arg::with_name("null")
            .short("0")
            .long("null")
            .help("end each output line with a 0 byte rather than a newline (only valid when \
                    printing the environment)"))
        .arg(Arg::with_name("file")
            .short("f")
            .long("file")
            .takes_value(true)
            .number_of_values(1)
            .value_name("PATH")
            .multiple(true)
            .help("read and set variables from a \".env\"-style configuration file (prior to any \
                    unset and/or set)"))
        .arg(Arg::with_name("unset")
            .short("u")
            .long("unset")
            .takes_value(true)
            .number_of_values(1)
            .value_name("NAME")
            .multiple(true)
            .help("remove variable from the environment"))
}

fn run_env(args: impl uucore::Args) -> UResult<()> {
    let app = uu_app();
    let matches = app.get_matches_from(args);

    let ignore_env = matches.is_present("ignore-environment");
    let null = matches.is_present("null");
    let running_directory = matches.value_of("chdir");
    let files = matches
        .values_of("file")
        .map(Iterator::collect)
        .unwrap_or_else(|| Vec::with_capacity(0));
    let unsets = matches
        .values_of("unset")
        .map(Iterator::collect)
        .unwrap_or_else(|| Vec::with_capacity(0));

    let mut opts = Options {
        ignore_env,
        null,
        running_directory,
        files,
        unsets,
        sets: vec![],
        program: vec![],
    };

    // change directory
    if let Some(d) = opts.running_directory {
        match env::set_current_dir(d) {
            Ok(()) => d,
            Err(error) => {
                return Err(USimpleError::new(
                    125,
                    format!("cannot change directory to \"{}\": {}", d, error),
                ));
            }
        };
    }

    // we handle the name, value pairs and the program to be executed by treating them as external
    // subcommands in clap
    if let (external, Some(matches)) = matches.subcommand() {
        let mut begin_prog_opts = false;

        if external == "-" {
            // "-" implies -i and stop parsing opts
            opts.ignore_env = true;
        } else {
            begin_prog_opts = parse_name_value_opt(&mut opts, external)?;
        }

        if let Some(mut iter) = matches.values_of("") {
            // read NAME=VALUE arguments (and up to a single program argument)
            while !begin_prog_opts {
                if let Some(opt) = iter.next() {
                    begin_prog_opts = parse_name_value_opt(&mut opts, opt)?;
                } else {
                    break;
                }
            }

            // read any leftover program arguments
            for opt in iter {
                parse_program_opt(&mut opts, opt)?;
            }
        }
    }

    // NOTE: we manually set and unset the env vars below rather than using Command::env() to more
    //       easily handle the case where no command is given

    // remove all env vars if told to ignore presets
    if opts.ignore_env {
        for (ref name, _) in env::vars() {
            env::remove_var(name);
        }
    }

    // load .env-style config file prior to those given on the command-line
    load_config_file(&mut opts)?;

    // unset specified env vars
    for name in &opts.unsets {
        env::remove_var(name);
    }

    // set specified env vars
    for &(name, val) in &opts.sets {
        // FIXME: set_var() panics if name is an empty string
        env::set_var(name, val);
    }

    if !opts.program.is_empty() {
        // we need to execute a command
        let (prog, args) = build_command(&mut opts.program);

        // FIXME: this should just use execvp() (no fork()) on Unix-like systems
        match Command::new(&*prog).args(args).status() {
            Ok(exit) if !exit.success() => return Err(exit.code().unwrap().into()),
            Err(ref err) if err.kind() == io::ErrorKind::NotFound => return Err(127.into()),
            Err(_) => return Err(126.into()),
            Ok(_) => (),
        }
    } else {
        // no program provided, so just dump all env vars to stdout
        print_env(opts.null);
    }

    Ok(())
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    run_env(args)
}
<commit_msg>env: don't panic when name is empty<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jordi Boggiano <j.boggiano@seld.be>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

/* last synced with: env (GNU coreutils) 8.13 */

// spell-checker:ignore (ToDO) chdir execvp progname subcommand subcommands unsets setenv putenv

#[macro_use]
extern crate clap;

#[macro_use]
extern crate uucore;

use clap::{App, AppSettings, Arg};
use ini::Ini;
use std::borrow::Cow;
use std::env;
use std::io::{self, Write};
use std::iter::Iterator;
use std::process::Command;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError};

const USAGE: &str = "env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]";
const AFTER_HELP: &str = "\
A mere - implies -i. If no COMMAND, print the resulting environment.
";

struct Options<'a> {
    ignore_env: bool,
    null: bool,
    running_directory: Option<&'a str>,
    files: Vec<&'a str>,
    unsets: Vec<&'a str>,
    sets: Vec<(&'a str, &'a str)>,
    program: Vec<&'a str>,
}

// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
fn print_env(null: bool) {
    let stdout_raw = io::stdout();
    let mut stdout = stdout_raw.lock();
    for (n, v) in env::vars() {
        write!(stdout, "{}={}{}", n, v, if null { '\0' } else { '\n' }).unwrap();
    }
}

fn parse_name_value_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<bool, i32> {
    // is it a NAME=VALUE like opt ?
    if let Some(idx) = opt.find('=') {
        // yes, so push name, value pair
        let (name, value) = opt.split_at(idx);
        opts.sets.push((name, &value['='.len_utf8()..]));

        Ok(false)
    } else {
        // no, it's a program-like opt
        parse_program_opt(opts, opt).map(|_| true)
    }
}

fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<(), i32> {
    if opts.null {
        eprintln!(
            "{}: cannot specify --null (-0) with command",
            uucore::util_name()
        );
        eprintln!(
            "Type \"{} --help\" for detailed information",
            uucore::execution_phrase()
        );
        Err(1)
    } else {
        opts.program.push(opt);
        Ok(())
    }
}

fn load_config_file(opts: &mut Options) -> UResult<()> {
    // NOTE: config files are parsed using an INI parser b/c it's available and compatible with ".env"-style files
    //   ... * but support for actual INI files, although working, is not intended, nor claimed
    for &file in &opts.files {
        let conf = if file == "-" {
            let stdin = io::stdin();
            let mut stdin_locked = stdin.lock();
            Ini::read_from(&mut stdin_locked)
        } else {
            Ini::load_from_file(file)
        };

        let conf = conf.map_err(|error| {
            show_error!("{}: {}", file.maybe_quote(), error);
            1
        })?;

        for (_, prop) in &conf {
            // ignore all INI section lines (treat them as comments)
            for (key, value) in prop.iter() {
                env::set_var(key, value);
            }
        }
    }

    Ok(())
}

#[cfg(not(windows))]
fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
    let progname = Cow::from(args[0]);
    (progname, &args[1..])
}

#[cfg(windows)]
fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
    args.insert(0, "/d/c");
    let progname = env::var("ComSpec")
        .map(Cow::from)
        .unwrap_or_else(|_| Cow::from("cmd"));

    (progname, &args[..])
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .usage(USAGE)
        .after_help(AFTER_HELP)
        .setting(AppSettings::AllowExternalSubcommands)
        .arg(Arg::with_name("ignore-environment")
            .short("i")
            .long("ignore-environment")
            .help("start with an empty environment"))
        .arg(Arg::with_name("chdir")
            .short("c")
            .long("chdir")
            .takes_value(true)
            .number_of_values(1)
            .value_name("DIR")
            .help("change working directory to DIR"))
        .arg(Arg::with_name("null")
            .short("0")
            .long("null")
            .help("end each output line with a 0 byte rather than a newline (only valid when \
                    printing the environment)"))
        .arg(Arg::with_name("file")
            .short("f")
            .long("file")
            .takes_value(true)
            .number_of_values(1)
            .value_name("PATH")
            .multiple(true)
            .help("read and set variables from a \".env\"-style configuration file (prior to any \
                    unset and/or set)"))
        .arg(Arg::with_name("unset")
            .short("u")
            .long("unset")
            .takes_value(true)
            .number_of_values(1)
            .value_name("NAME")
            .multiple(true)
            .help("remove variable from the environment"))
}

fn run_env(args: impl uucore::Args) -> UResult<()> {
    let app = uu_app();
    let matches = app.get_matches_from(args);

    let ignore_env = matches.is_present("ignore-environment");
    let null = matches.is_present("null");
    let running_directory = matches.value_of("chdir");
    let files = matches
        .values_of("file")
        .map(Iterator::collect)
        .unwrap_or_else(|| Vec::with_capacity(0));
    let unsets = matches
        .values_of("unset")
        .map(Iterator::collect)
        .unwrap_or_else(|| Vec::with_capacity(0));

    let mut opts = Options {
        ignore_env,
        null,
        running_directory,
        files,
        unsets,
        sets: vec![],
        program: vec![],
    };

    // change directory
    if let Some(d) = opts.running_directory {
        match env::set_current_dir(d) {
            Ok(()) => d,
            Err(error) => {
                return Err(USimpleError::new(
                    125,
                    format!("cannot change directory to \"{}\": {}", d, error),
                ));
            }
        };
    }

    // we handle the name, value pairs and the program to be executed by treating them as external
    // subcommands in clap
    if let (external, Some(matches)) = matches.subcommand() {
        let mut begin_prog_opts = false;

        if external == "-" {
            // "-" implies -i and stop parsing opts
            opts.ignore_env = true;
        } else {
            begin_prog_opts = parse_name_value_opt(&mut opts, external)?;
        }

        if let Some(mut iter) = matches.values_of("") {
            // read NAME=VALUE arguments (and up to a single program argument)
            while !begin_prog_opts {
                if let Some(opt) = iter.next() {
                    begin_prog_opts = parse_name_value_opt(&mut opts, opt)?;
                } else {
                    break;
                }
            }

            // read any leftover program arguments
            for opt in iter {
                parse_program_opt(&mut opts, opt)?;
            }
        }
    }

    // NOTE: we manually set and unset the env vars below rather than using Command::env() to more
    //       easily handle the case where no command is given

    // remove all env vars if told to ignore presets
    if opts.ignore_env {
        for (ref name, _) in env::vars() {
            env::remove_var(name);
        }
    }

    // load .env-style config file prior to those given on the command-line
    load_config_file(&mut opts)?;

    // unset specified env vars
    for name in &opts.unsets {
        env::remove_var(name);
    }

    // set specified env vars
    for &(name, val) in &opts.sets {
        /*
         * set_var panics if name is an empty string
         * set_var internally calls setenv (on unix at least), while GNU env calls putenv instead.
         *
         * putenv returns successfully if provided with something like "=a" and modifies the environ
         * variable to contain "=a" inside it, effectively modifying the process' current environment
         * to contain a malformed string in it. Using GNU's implementation, the command `env =a`
         * prints out the malformed string and even invokes the child process with that environment.
         * This can be seen by using `env -i =a env` or `env -i =a cat /proc/self/environ`
         *
         * POSIX.1-2017 doesn't seem to mention what to do if the string is malformed (at least
         * not in "Chapter 8, Environment Variables" or in the definition for environ and various
         * exec*'s or in the description of env in the "Shell & Utilities" volume).
         *
         * It also doesn't specify any checks for putenv before modifying the environ variable, which
         * is likely why glibc doesn't do so. However, setenv's first argument cannot point to
         * an empty string or a string containing '='.
         *
         * There is no benefit in replicating GNU's env behavior, since it will only modify the
         * environment in weird ways
         */

        if name.is_empty() {
            show_warning!("no name specified for value {}", val.quote());
            continue;
        }
        env::set_var(name, val);
    }

    if !opts.program.is_empty() {
        // we need to execute a command
        let (prog, args) = build_command(&mut opts.program);

        // FIXME: this should just use execvp() (no fork()) on Unix-like systems
        match Command::new(&*prog).args(args).status() {
            Ok(exit) if !exit.success() => return Err(exit.code().unwrap().into()),
            Err(ref err) if err.kind() == io::ErrorKind::NotFound => return Err(127.into()),
            Err(_) => return Err(126.into()),
            Ok(_) => (),
        }
    } else {
        // no program provided, so just dump all env vars to stdout
        print_env(opts.null);
    }

    Ok(())
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    run_env(args)
}
<|endoftext|>


<commit_before>//Write a program that prints the numbers from 1 to 100.
// But for multiples of three print “Fizz” instead of the number and
// for the multiples of five print “Buzz”.
// For numbers which are multiples of both three and five print “FizzBuzz

fn main() {
  for i in range(1, 101) {
    match i {
      i if i % 15 == 0 => { println("FizzBuzz") }
      i if i % 3 == 0 => { println("Fizz") }
      i if i % 5 == 0 => { println("Buzz") }
      _ => { println!("{}", i) }
    }
  }
}
<commit_msg>Update FizzBuzz<commit_after>// Write a program that prints the numbers from 1 to 100.
// But for multiples of three, print “Fizz” instead of the number,
// and for multiples of five, print “Buzz”.
// For numbers that are multiples of both three and five,
// print “FizzBuzz”.

fn main() {
  for i in range(1, 101) {
    println(
      match i {
        _ if i % 15 == 0 => ~"FizzBuzz",
        _ if i % 3 == 0 => ~"Fizz",
        _ if i % 5 == 0 => ~"Buzz",
        _ => i.to_str()
      }
    );
  }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use internal::{Err, IResult, ParseError};
use util::ErrorKind;

pub fn or<I: Clone, O, E: ParseError<I>, F, G>(f: F, g: G) -> impl Fn(I) -> IResult<I, O, E>
where
  F: Fn(I) -> IResult<I, O, E>,
  G: Fn(I) -> IResult<I, O, E>,
{
  move |i: I| {
    match f(i.clone()) {
      Err(Err::Error(e)) => g(i),
      res => res
    }
  }
}

pub trait Alt<I,O,E> {
  fn parse(&self, input: I) -> IResult<I,O,E>;
}

macro_rules! tuple_choice(
  ($first:ident $second:ident $($id: ident)+) => (
    tuple_choice!(__impl $first $second; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
    tuple_choice_impl!($($current)*);

    tuple_choice!(__impl $($current)* $head; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident) => (
    tuple_choice_impl!($($current)*);
    tuple_choice_impl!($($current)* $head);
  );
);

macro_rules! tuple_choice_impl(
  ($($id:ident)+) => (
    impl<
      Input: Clone, Output, Error: ParseError<Input>,
      $($id: Fn(Input) -> IResult<Input, Output, Error>),+
    > Alt<Input, Output, Error> for ( $($id),+ ) {

      fn parse(&self, input: Input) -> IResult<Input, Output, Error> {
        let mut err = None;
        tuple_choice_inner!(0, self, input, err, $($id)+);

        Err(Err::Error(Error::append(input, ErrorKind::Alt, err.unwrap())))
      }
    }
  );
);

macro_rules! tuple_choice_inner(
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
    match acc!($it, $self)($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
        succ!($it, tuple_choice_inner!($self, $input, $err, $($id)+))
      },
      res => return res,
    }
  );
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
    match acc!($it, $self)($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
      },
      res => return res,
    }
  );
);

tuple_choice!(A B C D E F G H I J K L M N O P Q R S T U);

pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I,O,E>>(l: List)  -> impl Fn(I) -> IResult<I, O, E> {
  move |i: I| {
    l.parse(i)
  }
}

<commit_msg>assemble errors in the or combinator<commit_after>#[macro_use]
mod macros;

use internal::{Err, IResult, ParseError};
use util::ErrorKind;

pub fn or<I: Clone, O, E: ParseError<I>, F, G>(f: F, g: G) -> impl Fn(I) -> IResult<I, O, E>
where
  F: Fn(I) -> IResult<I, O, E>,
  G: Fn(I) -> IResult<I, O, E>,
{
  move |i: I| {
    match f(i.clone()) {
      Err(Err::Error(e)) => g(i).map_err(|e2| match e2 {
        Err::Error(e2) => Err::Error(e.or(e2)),
        e2 => e2,
      }),
      res => res
    }
  }
}

pub trait Alt<I,O,E> {
  fn parse(&self, input: I) -> IResult<I,O,E>;
}

macro_rules! tuple_choice(
  ($first:ident $second:ident $($id: ident)+) => (
    tuple_choice!(__impl $first $second; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
    tuple_choice_impl!($($current)*);

    tuple_choice!(__impl $($current)* $head; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident) => (
    tuple_choice_impl!($($current)*);
    tuple_choice_impl!($($current)* $head);
  );
);

macro_rules! tuple_choice_impl(
  ($($id:ident)+) => (
    impl<
      Input: Clone, Output, Error: ParseError<Input>,
      $($id: Fn(Input) -> IResult<Input, Output, Error>),+
    > Alt<Input, Output, Error> for ( $($id),+ ) {

      fn parse(&self, input: Input) -> IResult<Input, Output, Error> {
        let mut err = None;
        tuple_choice_inner!(0, self, input, err, $($id)+);

        Err(Err::Error(Error::append(input, ErrorKind::Alt, err.unwrap())))
      }
    }
  );
);

macro_rules! tuple_choice_inner(
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
    match acc!($it, $self)($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
        succ!($it, tuple_choice_inner!($self, $input, $err, $($id)+))
      },
      res => return res,
    }
  );
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
    match acc!($it, $self)($input.clone()) {
      Err(Err::Error(e)) => {
        if $err.is_none() {
          $err = Some(e);
        } else {
          $err = Some($err.unwrap().or(e));
        }
      },
      res => return res,
    }
  );
);

tuple_choice!(A B C D E F G H I J K L M N O P Q R S T U);

pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I,O,E>>(l: List)  -> impl Fn(I) -> IResult<I, O, E> {
  move |i: I| {
    l.parse(i)
  }
}

<|endoftext|>


<commit_before>use std::result::Result as RResult;
use std::path::Path;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;

use libimagstore::store::{FileLockEntry, Store};
use libimagref::reference::Ref;
use libimagref::flags::RefFlags;

use mailparse::{MailParseError, ParsedMail, parse_mail};

use hasher::MailHasher;
use result::Result;
use error::{MapErrInto, MailErrorKind as MEK};

struct Buffer(String);

impl Buffer {
    pub fn parsed<'a>(&'a self) -> RResult<ParsedMail<'a>, MailParseError> {
        parse_mail(self.0.as_bytes())
    }
}

impl From<String> for Buffer {
    fn from(data: String) -> Buffer {
        Buffer(data)
    }
}

pub struct Mail<'a>(Ref<'a>, Buffer);

impl<'a> Mail<'a> {

    /// Imports a mail from the Path passed
    pub fn import_from_path<P: AsRef<Path>>(store: &Store, p: P) -> Result<Mail> {
        let h = MailHasher::new();
        let f = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
        let p = PathBuf::from(p.as_ref());

        Ref::create_with_hasher(store, p, f, h)
            .map_err_into(MEK::RefCreationError)
            .and_then(|reference| {
                reference.fs_file()
                    .map_err_into(MEK::RefHandlingError)
                    .and_then(|path| File::open(path).map_err_into(MEK::IOError))
                    .and_then(|mut file| {
                        let mut s = String::new();
                        file.read_to_string(&mut s)
                            .map(|_| s)
                            .map_err_into(MEK::IOError)
                    })
                    .map(Buffer::from)
                    .map(|buffer| Mail(reference, buffer))
            })
    }

    /// Opens a mail by the passed hash
    pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
        let r = try!(Ref::get_by_hash(store, String::from(hash.as_ref()))
            .map_err_into(MEK::FetchByHashError)
            .map_err_into(MEK::FetchError));

        if r.is_none() {
            return Ok(None);
        }
        let r = r.unwrap();

        r.fs_file()
            .map_err_into(MEK::RefHandlingError)
            .and_then(|path| File::open(path).map_err_into(MEK::IOError))
            .and_then(|mut file| {
                let mut s = String::new();
                file.read_to_string(&mut s)
                    .map(|_| s)
                    .map_err_into(MEK::IOError)
            })
            .map(Buffer::from)
            .map(|buffer| Some(Mail(r, buffer)))
    }

    pub fn get_field<S: AsRef<str>>(&self, field: S) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_from(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_to(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_subject(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_message_id(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_in_reply_to(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

}
<commit_msg>Impl Mail::get_field()<commit_after>use std::result::Result as RResult;
use std::path::Path;
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;

use libimagstore::store::{FileLockEntry, Store};
use libimagref::reference::Ref;
use libimagref::flags::RefFlags;

use mailparse::{MailParseError, ParsedMail, parse_mail};

use hasher::MailHasher;
use result::Result;
use error::{MapErrInto, MailErrorKind as MEK};

struct Buffer(String);

impl Buffer {
    pub fn parsed<'a>(&'a self) -> RResult<ParsedMail<'a>, MailParseError> {
        parse_mail(self.0.as_bytes())
    }
}

impl From<String> for Buffer {
    fn from(data: String) -> Buffer {
        Buffer(data)
    }
}

pub struct Mail<'a>(Ref<'a>, Buffer);

impl<'a> Mail<'a> {

    /// Imports a mail from the Path passed
    pub fn import_from_path<P: AsRef<Path>>(store: &Store, p: P) -> Result<Mail> {
        let h = MailHasher::new();
        let f = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
        let p = PathBuf::from(p.as_ref());

        Ref::create_with_hasher(store, p, f, h)
            .map_err_into(MEK::RefCreationError)
            .and_then(|reference| {
                reference.fs_file()
                    .map_err_into(MEK::RefHandlingError)
                    .and_then(|path| File::open(path).map_err_into(MEK::IOError))
                    .and_then(|mut file| {
                        let mut s = String::new();
                        file.read_to_string(&mut s)
                            .map(|_| s)
                            .map_err_into(MEK::IOError)
                    })
                    .map(Buffer::from)
                    .map(|buffer| Mail(reference, buffer))
            })
    }

    /// Opens a mail by the passed hash
    pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
        let r = try!(Ref::get_by_hash(store, String::from(hash.as_ref()))
            .map_err_into(MEK::FetchByHashError)
            .map_err_into(MEK::FetchError));

        if r.is_none() {
            return Ok(None);
        }
        let r = r.unwrap();

        r.fs_file()
            .map_err_into(MEK::RefHandlingError)
            .and_then(|path| File::open(path).map_err_into(MEK::IOError))
            .and_then(|mut file| {
                let mut s = String::new();
                file.read_to_string(&mut s)
                    .map(|_| s)
                    .map_err_into(MEK::IOError)
            })
            .map(Buffer::from)
            .map(|buffer| Some(Mail(r, buffer)))
    }

    pub fn get_field(&self, field: &str) -> Result<Option<String>> {
        use mailparse::MailHeader;

        self.1
            .parsed()
            .map_err_into(MEK::MailParsingError)
            .map(|parsed| {
                parsed.headers
                    .iter()
                    .filter(|hdr| hdr.get_key().map(|n| n == field).unwrap_or(false))
                    .next()
                    .and_then(|field| field.get_value().ok())
            })
    }

    pub fn get_from(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_to(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_subject(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_message_id(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

    pub fn get_in_reply_to(&self) -> Result<Option<&str>> {
        unimplemented!()
    }

}
<|endoftext|>


<commit_before>mod render;

use self::render::*;
use super::module::*;

use glutin::{self, Api, ContextBuilder, ControlFlow, EventsLoop, GlContext, GlRequest, Window,
             WindowBuilder, WindowEvent};
use modular_flow as mf;

use std::env;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use gfx;
use gfx::texture;
use gfx::traits::{Factory, FactoryExt};
use gfx::{Bind, CommandBuffer, Device, Encoder, IntoIndexBuffer, PipelineState, Resources, Slice};
use gfx::memory::Usage;
use gfx::buffer::Role;
use gfx::handle::{Buffer, DepthStencilView, RenderTargetView, Sampler, ShaderResourceView, Texture};
use gfx_window_glutin as gfx_glutin;
use gfx_text;
use gfx_device_gl as gl;

pub fn gui_main() {
    let mut model = Model::new();
    main_loop(&mut model);
}

type Graph = mf::Graph<Mutex<Box<GuiModule>>>;
type Interface = mf::Interface<Mutex<Box<GuiModule>>>;

/// Model holds info about GUI state
/// and program state
struct Model {
    time: f32,
    graph: Arc<Graph>,
    window_size: [f32; 2],
    mouse_pos: [f32; 2],
    node_z: Vec<mf::NodeId>,
}

impl Model {
    fn new() -> Model {
        Model {
            graph: Graph::new(),
            time: 0.0,
            window_size: [0.0, 0.0],
            mouse_pos: [0.0, 0.0],
            node_z: Vec::new(),
        }
    }

    fn update_depth(&mut self) {
        use std::collections::HashSet;
        let graph_nodes = self.graph.node_map();
        let mut seen = HashSet::new();
        self.node_z.drain_filter(|node| {
            seen.insert(*node);
            !graph_nodes.contains_key(node)
        });
        for (id, _) in &graph_nodes {
            if !seen.contains(id) {
                self.node_z.push(*id);
            }
        }
    }
    fn update(&mut self) {
        self.update_depth();
    }

    fn handle_mouse_input(&mut self, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;

        let graph_nodes = self.graph.node_map();
        let mut hit = false;
        let mut idx = self.node_z.len();
        for id in self.node_z.iter() {
            idx -= 1;
            if let Some(node) = graph_nodes.get(id) {
                let mut module = node.module().lock().unwrap();
                let rect = *module.window_rect();
                if point_in_rect(self.mouse_pos, &rect) {
                    module.handle_click(self, state, button);
                    hit = true;
                    break;
                }
            }
        }
        if hit {
            let removed = self.node_z.remove(idx);
            self.node_z.push(removed);
        }
    }

    fn handle(&mut self, event: &glutin::Event) {
        use glutin::WindowEvent::*;
        use glutin::*;
        //println!("{:?}", event);
        match event {
            glutin::Event::WindowEvent {
                window_id: _,
                event,
            } => match event {
                Resized(w, h) => {
                    self.window_size = [*w as f32, *h as f32];
                }
                CursorMoved {
                    device_id: _,
                    position,
                } => {
                    self.mouse_pos = [position.0 as f32, position.1 as f32];
                }
                MouseInput {
                    device_id: _,
                    state,
                    button,
                } => {
                    self.handle_mouse_input(&state, &button);
                }
                _ => (),
            },
            _ => (),
        }
    }
}

fn main_loop(model: &mut Model) {
    // init window
    let mut events_loop = EventsLoop::new();
    let context = ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
    let builder = WindowBuilder::new().with_title(String::from("flow-synth"));
    let (window, mut device, mut factory, mut main_color, mut main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    let mut target = Target {
        color: main_color,
        depth: main_depth,
    };

    // init rendering pipeline
    let mut ctx = RenderContext::new(factory.clone());

    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "foo",
        Arc::new(move |ifc| {
            Mutex::new(Box::new(GuiModuleWrapper::new(
                TestModule::new(ifc),
                mod_ctx.clone(),
            )))
        }),
    ));
    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "bar",
        Arc::new(move |ifc| {
            let mut w = GuiModuleWrapper::new(TestModule::new(ifc), mod_ctx.clone());
            w.window_rect.translate[0] = 256.0;
            Mutex::new(Box::new(w))
        }),
    ));

    // begin main loop
    let mut running = true;
    let timer = Instant::now();
    let mut frames = VecDeque::new();
    while running {
        let now = timer.elapsed();
        model.time = now.as_secs() as f32 + now.subsec_nanos() as f32 / 1_000_000_000.0;
        frames.push_back(model.time);
        while let Some(&old_frame) = frames.front() {
            if old_frame < model.time - 1.0 {
                frames.pop_front();
            } else {
                break;
            }
        }
        model.update();
        for node in model.graph.nodes() {
            let mut module = node.module().lock().unwrap();
            module.update(&model);
        }
        events_loop.poll_events(|event| {
            model.handle(&event);
            for node in model.graph.nodes() {
                let mut module = node.module().lock().unwrap();
                module.handle(&model, &event);
            }
            use glutin::WindowEvent::*;
            match event {
                glutin::Event::WindowEvent {
                    window_id: _,
                    event,
                } => match event {
                    Closed => running = false,
                    Resized(_, _) => {
                        gfx_glutin::update_views(&window, &mut target.color, &mut target.depth);
                    }
                    _ => (),
                },
                _ => (),
            }
        });

        ctx.begin_frame(&target);

        let mut z_idx = 0;
        let graph_nodes = model.graph.node_map();
        for id in &model.node_z {
            match graph_nodes.get(id) {
                Some(node) => {
                    let mut module = node.module().lock().unwrap();
                    module.render(&mut device, &mut ctx, z_idx);
                    z_idx += 1;
                }
                None => (), // node was removed between call to model.update() and here. safe to ignore
            }
        }

        // debug text
        ctx.draw_text(
            &format!("FPS={} Time={}", frames.len(), model.time),
            [0.0, 0.0],
            [1.0, 1.0, 1.0],
        );

        ctx.end_frame(&mut device, &target);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

trait GuiModule: Module {
    fn render(&mut self, &mut gl::Device, &mut RenderContext, i32);
    fn window_rect(&self) -> &Rect;

    fn update(&mut self, model: &Model);
    fn handle(&mut self, model: &Model, event: &glutin::Event);
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton);
}
struct GuiModuleWrapper<T: Module> {
    module: T,

    window_rect: Rect,
    size: [f32; 2],
    drag: Option<[f32; 2]>,

    internal_ctx: RenderContext,
    module_target_texture: Texture<gl::Resources, gfx::format::R8_G8_B8_A8>,
    module_depth_texture: Texture<gl::Resources, gfx::format::D24_S8>,
    module_target_resource: ShaderResourceView<gl::Resources, [f32; 4]>,
    module_target: Target,
}

impl<T: Module> GuiModuleWrapper<T> {
    fn new(module: T, ctx: RenderContext) -> GuiModuleWrapper<T> {
        let mut factory = ctx.factory().clone();
        let size = [256.0; 2];
        let module_target_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_color_target = factory
            .view_texture_as_render_target(
                &module_target_texture,
                0,    //level
                None, //layer
            )
            .unwrap();
        let module_target_resource = factory
            .view_texture_as_shader_resource::<gfx::format::Rgba8>(
                &module_target_texture,
                (0, 0), // levels
                gfx::format::Swizzle::new(),
            )
            .unwrap();

        let module_depth_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::DEPTH_STENCIL,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_depth_target = factory
            .view_texture_as_depth_stencil(
                &module_depth_texture,
                0,    //level
                None, //layer
                texture::DepthStencilFlags::empty(),
            )
            .unwrap();

        let module_target = Target {
            color: module_color_target,
            depth: module_depth_target,
        };

        GuiModuleWrapper {
            module,
            window_rect: Rect {
                translate: [0.0, 0.0, 0.0],
                scale: size,
            },
            size,
            drag: None,
            internal_ctx: ctx,
            module_target_resource,
            module_target_texture,
            module_depth_texture,
            module_target,
        }
    }
}

impl<T> GuiModule for GuiModuleWrapper<T>
where
    T: Module,
{
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext, z_idx: i32) {
        self.internal_ctx.begin_frame(&self.module_target);

        self.internal_ctx.draw_rect(ColoredRect {
            translate: [0.0, 0.0, 0.0],
            scale: self.size,
            color: [1.0, 1.0, 1.0],
        });
        let title = &self.title();
        self.internal_ctx
            .draw_text(title, [16.0, 16.0], [0.0, 0.0, 0.0]);

        self.internal_ctx.end_frame(device, &self.module_target);

        self.window_rect.translate[2] = z_idx as f32;
        ctx.draw_textured_rect(self.window_rect, self.module_target_resource.clone());
    }
    fn update(&mut self, model: &Model) {
        if let Some(drag) = self.drag {
            self.window_rect.translate = [
                -drag[0] + model.mouse_pos[0],
                -drag[1] + model.mouse_pos[1],
                0.0,
            ];
        }
    }
    fn handle(&mut self, model: &Model, event: &glutin::Event) {}
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;
        match button {
            MouseButton::Left => match state {
                ElementState::Pressed => {
                    self.drag = Some([
                        model.mouse_pos[0] - self.window_rect.translate[0],
                        model.mouse_pos[1] - self.window_rect.translate[1],
                    ]);
                }
                ElementState::Released => {
                    self.drag = None;
                }
            },
            _ => {}
        }
    }
    fn window_rect(&self) -> &Rect {
        &self.window_rect
    }
}
impl<T> Module for GuiModuleWrapper<T>
where
    T: Module,
{
    fn start(&mut self) {
        T::start(&mut self.module);
    }
    fn title(&self) -> String {
        T::title(&self.module)
    }
}
<commit_msg>don't render if not dirty<commit_after>mod render;

use self::render::*;
use super::module::*;

use glutin::{self, Api, ContextBuilder, ControlFlow, EventsLoop, GlContext, GlRequest, Window,
             WindowBuilder, WindowEvent};
use modular_flow as mf;

use std::env;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use gfx;
use gfx::texture;
use gfx::traits::{Factory, FactoryExt};
use gfx::{Bind, CommandBuffer, Device, Encoder, IntoIndexBuffer, PipelineState, Resources, Slice};
use gfx::memory::Usage;
use gfx::buffer::Role;
use gfx::handle::{Buffer, DepthStencilView, RenderTargetView, Sampler, ShaderResourceView, Texture};
use gfx_window_glutin as gfx_glutin;
use gfx_text;
use gfx_device_gl as gl;

pub fn gui_main() {
    let mut model = Model::new();
    main_loop(&mut model);
}

type Graph = mf::Graph<Mutex<Box<GuiModule>>>;
type Interface = mf::Interface<Mutex<Box<GuiModule>>>;

/// Model holds info about GUI state
/// and program state
struct Model {
    time: f32,
    graph: Arc<Graph>,
    window_size: [f32; 2],
    mouse_pos: [f32; 2],
    node_z: Vec<mf::NodeId>,
}

impl Model {
    fn new() -> Model {
        Model {
            graph: Graph::new(),
            time: 0.0,
            window_size: [0.0, 0.0],
            mouse_pos: [0.0, 0.0],
            node_z: Vec::new(),
        }
    }

    fn update_depth(&mut self) {
        use std::collections::HashSet;
        let graph_nodes = self.graph.node_map();
        let mut seen = HashSet::new();
        self.node_z.drain_filter(|node| {
            seen.insert(*node);
            !graph_nodes.contains_key(node)
        });
        for (id, _) in &graph_nodes {
            if !seen.contains(id) {
                self.node_z.push(*id);
            }
        }
    }
    fn update(&mut self) {
        self.update_depth();
    }

    fn handle_mouse_input(&mut self, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;

        let graph_nodes = self.graph.node_map();
        let mut hit = false;
        let mut idx = self.node_z.len();
        for id in self.node_z.iter() {
            idx -= 1;
            if let Some(node) = graph_nodes.get(id) {
                let mut module = node.module().lock().unwrap();
                let rect = *module.window_rect();
                if point_in_rect(self.mouse_pos, &rect) {
                    module.handle_click(self, state, button);
                    hit = true;
                    break;
                }
            }
        }
        if hit {
            let removed = self.node_z.remove(idx);
            self.node_z.push(removed);
        }
    }

    fn handle(&mut self, event: &glutin::Event) {
        use glutin::WindowEvent::*;
        use glutin::*;
        //println!("{:?}", event);
        match event {
            glutin::Event::WindowEvent {
                window_id: _,
                event,
            } => match event {
                Resized(w, h) => {
                    self.window_size = [*w as f32, *h as f32];
                }
                CursorMoved {
                    device_id: _,
                    position,
                } => {
                    self.mouse_pos = [position.0 as f32, position.1 as f32];
                }
                MouseInput {
                    device_id: _,
                    state,
                    button,
                } => {
                    self.handle_mouse_input(&state, &button);
                }
                _ => (),
            },
            _ => (),
        }
    }
}

fn main_loop(model: &mut Model) {
    // init window
    let mut events_loop = EventsLoop::new();
    let context = ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
    let builder = WindowBuilder::new().with_title(String::from("flow-synth"));
    let (window, mut device, mut factory, mut main_color, mut main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    let mut target = Target {
        color: main_color,
        depth: main_depth,
    };

    // init rendering pipeline
    let mut ctx = RenderContext::new(factory.clone());

    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "foo",
        Arc::new(move |ifc| {
            Mutex::new(Box::new(GuiModuleWrapper::new(
                TestModule::new(ifc),
                mod_ctx.clone(),
            )))
        }),
    ));
    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "bar",
        Arc::new(move |ifc| {
            let mut w = GuiModuleWrapper::new(TestModule::new(ifc), mod_ctx.clone());
            w.window_rect.translate[0] = 256.0;
            Mutex::new(Box::new(w))
        }),
    ));

    // begin main loop
    let mut running = true;
    let timer = Instant::now();
    let mut frames = VecDeque::new();
    while running {
        let now = timer.elapsed();
        model.time = now.as_secs() as f32 + now.subsec_nanos() as f32 / 1_000_000_000.0;
        frames.push_back(model.time);
        while let Some(&old_frame) = frames.front() {
            if old_frame < model.time - 1.0 {
                frames.pop_front();
            } else {
                break;
            }
        }
        model.update();
        for node in model.graph.nodes() {
            let mut module = node.module().lock().unwrap();
            module.update(&model);
        }
        events_loop.poll_events(|event| {
            model.handle(&event);
            for node in model.graph.nodes() {
                let mut module = node.module().lock().unwrap();
                module.handle(&model, &event);
            }
            use glutin::WindowEvent::*;
            match event {
                glutin::Event::WindowEvent {
                    window_id: _,
                    event,
                } => match event {
                    Closed => running = false,
                    Resized(_, _) => {
                        gfx_glutin::update_views(&window, &mut target.color, &mut target.depth);
                    }
                    _ => (),
                },
                _ => (),
            }
        });

        ctx.begin_frame(&target);

        let mut z_idx = 0;
        let graph_nodes = model.graph.node_map();
        for id in &model.node_z {
            match graph_nodes.get(id) {
                Some(node) => {
                    let mut module = node.module().lock().unwrap();
                    module.render(&mut device, &mut ctx, z_idx);
                    z_idx += 1;
                }
                None => (), // node was removed between call to model.update() and here. safe to ignore
            }
        }

        // debug text
        ctx.draw_text(
            &format!("FPS={} Time={}", frames.len(), model.time),
            [0.0, 0.0],
            [1.0, 1.0, 1.0],
        );

        ctx.end_frame(&mut device, &target);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

trait GuiModule: Module {
    fn render(&mut self, &mut gl::Device, &mut RenderContext, i32);
    fn window_rect(&self) -> &Rect;

    fn update(&mut self, model: &Model);
    fn handle(&mut self, model: &Model, event: &glutin::Event);
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton);
}
struct GuiModuleWrapper<T: Module> {
    module: T,

    window_rect: Rect,
    size: [f32; 2],
    drag: Option<[f32; 2]>,
    dirty: bool,

    internal_ctx: RenderContext,
    module_target_texture: Texture<gl::Resources, gfx::format::R8_G8_B8_A8>,
    module_depth_texture: Texture<gl::Resources, gfx::format::D24_S8>,
    module_target_resource: ShaderResourceView<gl::Resources, [f32; 4]>,
    module_target: Target,
}

impl<T: Module> GuiModuleWrapper<T> {
    fn new(module: T, ctx: RenderContext) -> GuiModuleWrapper<T> {
        let mut factory = ctx.factory().clone();
        let size = [256.0; 2];
        let module_target_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_color_target = factory
            .view_texture_as_render_target(
                &module_target_texture,
                0,    //level
                None, //layer
            )
            .unwrap();
        let module_target_resource = factory
            .view_texture_as_shader_resource::<gfx::format::Rgba8>(
                &module_target_texture,
                (0, 0), // levels
                gfx::format::Swizzle::new(),
            )
            .unwrap();

        let module_depth_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::DEPTH_STENCIL,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_depth_target = factory
            .view_texture_as_depth_stencil(
                &module_depth_texture,
                0,    //level
                None, //layer
                texture::DepthStencilFlags::empty(),
            )
            .unwrap();

        let module_target = Target {
            color: module_color_target,
            depth: module_depth_target,
        };

        GuiModuleWrapper {
            module,
            window_rect: Rect {
                translate: [0.0, 0.0, 0.0],
                scale: size,
            },
            size,
            drag: None,
            dirty: true,
            internal_ctx: ctx,
            module_target_resource,
            module_target_texture,
            module_depth_texture,
            module_target,
        }
    }
    fn render_self(&mut self) {
        self.internal_ctx.draw_rect(ColoredRect {
            translate: [0.0, 0.0, 0.0],
            scale: self.size,
            color: [1.0, 1.0, 1.0],
        });
        let title = &self.title();
        self.internal_ctx
            .draw_text(title, [16.0, 16.0], [0.0, 0.0, 0.0]);
    }
}

impl<T> GuiModule for GuiModuleWrapper<T>
where
    T: Module,
{
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext, z_idx: i32) {
        if self.dirty {
            self.internal_ctx.begin_frame(&self.module_target);
            self.render_self();
            self.internal_ctx.end_frame(device, &self.module_target);
            self.dirty = false;
        }

        self.window_rect.translate[2] = z_idx as f32;
        ctx.draw_textured_rect(self.window_rect, self.module_target_resource.clone());
    }
    fn update(&mut self, model: &Model) {
        if let Some(drag) = self.drag {
            self.window_rect.translate = [
                -drag[0] + model.mouse_pos[0],
                -drag[1] + model.mouse_pos[1],
                0.0,
            ];
        }
    }
    fn handle(&mut self, model: &Model, event: &glutin::Event) {}
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;
        match button {
            MouseButton::Left => match state {
                ElementState::Pressed => {
                    self.drag = Some([
                        model.mouse_pos[0] - self.window_rect.translate[0],
                        model.mouse_pos[1] - self.window_rect.translate[1],
                    ]);
                }
                ElementState::Released => {
                    self.drag = None;
                }
            },
            _ => {}
        }
    }
    fn window_rect(&self) -> &Rect {
        &self.window_rect
    }
}
impl<T> Module for GuiModuleWrapper<T>
where
    T: Module,
{
    fn start(&mut self) {
        T::start(&mut self.module);
    }
    fn title(&self) -> String {
        T::title(&self.module)
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::mem_drain::MemDrain;
use lazy_static::lazy_static;
use slog::{o, Drain, Logger};
use std::{
    boxed::Box,
    sync::{Arc, Mutex},
};

lazy_static! {
    static ref BUFFER: Arc<Mutex<MemDrain>> = Arc::new(Mutex::new(MemDrain::default()));
}

pub fn init(level: slog::Level) {
    let buffer_drain = buffer().filter_level(level).fuse();
    let terminal_drain = Mutex::new(slog_term::term_full().filter_level(level)).fuse();
    let terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();

    let log = Logger::root(slog::Duplicate::new(buffer_drain, terminal_drain).fuse(), o!());

    // FIXME: Drop the use of Box::leak here (issue #23).
    let guard = slog_scope::set_global_logger(log);
    Box::leak(Box::new(guard));
}

pub fn buffer() -> Arc<Mutex<MemDrain>> {
    BUFFER.clone()
}

pub fn start_memory_logging() {
    BUFFER.lock().unwrap().start_logging()
}

pub fn stop_memory_logging() {
    BUFFER.lock().unwrap().stop_logging()
}

pub fn get_memory_log() -> String {
    BUFFER.lock().unwrap().to_string()
}
<commit_msg>updatehub: Remove colored log<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::mem_drain::MemDrain;
use lazy_static::lazy_static;
use slog::{o, Drain, Logger};
use std::{
    boxed::Box,
    sync::{Arc, Mutex},
};

lazy_static! {
    static ref BUFFER: Arc<Mutex<MemDrain>> = Arc::new(Mutex::new(MemDrain::default()));
}

pub fn init(level: slog::Level) {
    let buffer_drain = buffer().filter_level(level).fuse();
    let terminal_drain = Mutex::new(
        slog_term::FullFormat::new(slog_term::TermDecorator::new().force_plain().build())
            .build()
            .filter_level(level),
    )
    .fuse();
    let terminal_drain = slog_async::Async::new(terminal_drain).build().fuse();

    let log = Logger::root(slog::Duplicate::new(buffer_drain, terminal_drain).fuse(), o!());

    // FIXME: Drop the use of Box::leak here (issue #23).
    let guard = slog_scope::set_global_logger(log);
    Box::leak(Box::new(guard));
}

pub fn buffer() -> Arc<Mutex<MemDrain>> {
    BUFFER.clone()
}

pub fn start_memory_logging() {
    BUFFER.lock().unwrap().start_logging()
}

pub fn stop_memory_logging() {
    BUFFER.lock().unwrap().stop_logging()
}

pub fn get_memory_log() -> String {
    BUFFER.lock().unwrap().to_string()
}
<|endoftext|>


<commit_before>#![crate_name = "hiredis"]
#![crate_type = "lib"]
#![feature(globs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]

extern crate libc;

use std::mem::transmute;

pub mod api;

pub struct Reply {
    head:  bool,
    reply: *const api::Reply
}

pub enum ReplyCode {
    String = 1,
    Array,
    Integer,
    Nil,
    Status,
    Error,
    Unknown
}

impl Reply {
    /**
     * Creates a new Reply wrapper.
     *
     * This wraps an already existing Reply returned from hiredis, it will
     * automatically free the data when the reply goes out of scope. Note that
     * this method cannot be invoked outside of the crate.
     */
    fn new(reply: *const api::Reply) -> Reply {
        Reply {
            head:  true,
            reply: reply
        }
    }

    /**
     * Redis replies with the type of data being sent, this method allows
     * peaking into it.
     *
     * TODO: Create a nicer wrapper enum that encodes the data directly with
     * Vectors and so on.
     */
    pub fn typename(&self) -> ReplyCode {
        unsafe {
            match (*self.reply)._type {
                1 => String,
                2 => Array,
                3 => Integer,
                4 => Nil,
                5 => Status,
                6 => Error,
                _ => Unknown
            }
        }
    }

    pub fn string<'r>(&'r self) -> Option<&'r [u8]> {
        match self.typename() {
            String => {
                unsafe {
                    let data = std::c_vec::CVec::new(
                        (*self.reply)._str as *mut u8,
                        (*self.reply).len as uint
                    ).as_mut_slice() as *mut [u8];

                    Some(&*data)
                }
            }

            _ => {
                None
            }
        }
    }
}

impl Drop for Reply {
    fn drop(&mut self) {
        unsafe {
            /* When Redis returns a Reply object, we wrap it in our own Reply
             * object. However, if redis returns an array, the Reply object
             * contains an array of sub Reply objects. These get wrapped too,
             * but should not be freed, as freeing the head object frees the
             * children too. This check prevents us accidentally freeing replies
             * that shouldn't be freed.
             */
            if self.head {
                api::freeReplyObject(transmute(self.reply))
            }
        }
    }
}

pub struct Redis {
    context: *const api::Context
}

impl Redis {
    /**
     * Creates a new connection to a Redis instance.
     *
     * TODO: Deal with the other redisConnect* variants, not yet sure how to
     * design this API.
     */
    pub fn new(ip: &str, port: i32) -> Redis {
        unsafe {
            Redis {
                context: api::redisConnect(
                    ip.to_c_str().as_ptr(),
                    port
                )
            }
        }
    }

    /**
     * Sends a single command to be executed, and returns the reply immediately.
     * If further replies are expected the `receive` function exists to expect
     * them. This function doesn't handle complex spaces in messages, and so the
     * `execf` function exists and uses hiredis's formatting instead.
     *
     * TODO: Move to IoResult using context.err
     */
    pub fn command(&self, command: &str) -> Option<Reply> {
        command.with_c_str(|v| {
            unsafe {
                /* This is the library call, returns (void*)0 on failure. */
                let result = api::redisCommand(self.context, v);

                /* Fail if the command errored for some reason. */
                if result == 0 as *const ::libc::c_void {
                    return None;
                }

                /* Otherwise cast the pointer to the actual struct type being
                 * returned and store it to be returned. */
                Some(Reply::new(result as *const api::Reply))
            }
        })
    }

    /**
     * Appends a command to the output buffer, allowing for pipelining.
     *
     * TODO: This needs to return a status code.
     */
    pub fn append_command(&self, command: &str) {
        command.with_c_str(|v| {
            unsafe {
                api::redisAppendCommand(self.context, v);
            }
        });
    }

    /**
     * Attempts to read a message from the input buffer. Blocking in this
     * context depends on how the connection was created.
     */
    pub fn receive(&self) -> Option<Reply> {
        unsafe {
            let reply: Reply = std::mem::uninitialized();
            let result       = api::redisGetReply(self.context, transmute(&reply));

            Some(reply)
        }
    }
}

impl Drop for Redis {
    /**
     * When a Redis instance goes out of scope, the connection needs to be
     * closed. Redis has a function for this that both closes the connection and
     * frees any resources used.
     */
    fn drop(&mut self) {
        unsafe {
            api::redisFree(self.context)
        }
    }
}
<commit_msg>Fix receive function using the wrong struct.<commit_after>#![crate_name = "hiredis"]
#![crate_type = "lib"]
#![feature(globs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]

extern crate libc;

use std::mem::transmute;

pub mod api;

pub struct Reply {
    head:  bool,
    reply: *const api::Reply
}

pub enum ReplyCode {
    String = 1,
    Array,
    Integer,
    Nil,
    Status,
    Error,
    Unknown
}

impl Reply {
    /**
     * Creates a new Reply wrapper.
     *
     * This wraps an already existing Reply returned from hiredis, it will
     * automatically free the data when the reply goes out of scope. Note that
     * this method cannot be invoked outside of the crate.
     */
    fn new(reply: *const api::Reply) -> Reply {
        Reply {
            head:  true,
            reply: reply
        }
    }

    /**
     * Redis replies with the type of data being sent, this method allows
     * peaking into it.
     *
     * TODO: Create a nicer wrapper enum that encodes the data directly with
     * Vectors and so on.
     */
    pub fn typename(&self) -> ReplyCode {
        unsafe {
            match (*self.reply)._type {
                1 => String,
                2 => Array,
                3 => Integer,
                4 => Nil,
                5 => Status,
                6 => Error,
                _ => Unknown
            }
        }
    }

    pub fn string<'r>(&'r self) -> Option<&'r [u8]> {
        match self.typename() {
            String => {
                unsafe {
                    let data = std::c_vec::CVec::new(
                        (*self.reply)._str as *mut u8,
                        (*self.reply).len as uint
                    ).as_mut_slice() as *mut [u8];

                    Some(&*data)
                }
            }

            _ => {
                None
            }
        }
    }
}

impl Drop for Reply {
    fn drop(&mut self) {
        unsafe {
            /* When Redis returns a Reply object, we wrap it in our own Reply
             * object. However, if redis returns an array, the Reply object
             * contains an array of sub Reply objects. These get wrapped too,
             * but should not be freed, as freeing the head object frees the
             * children too. This check prevents us accidentally freeing replies
             * that shouldn't be freed.
             */
            if self.head {
                api::freeReplyObject(transmute(self.reply))
            }
        }
    }
}

pub struct Redis {
    context: *const api::Context
}

impl Redis {
    /**
     * Creates a new connection to a Redis instance.
     *
     * TODO: Deal with the other redisConnect* variants, not yet sure how to
     * design this API.
     */
    pub fn new(ip: &str, port: i32) -> Redis {
        unsafe {
            Redis {
                context: api::redisConnect(
                    ip.to_c_str().as_ptr(),
                    port
                )
            }
        }
    }

    /**
     * Sends a single command to be executed, and returns the reply immediately.
     * If further replies are expected the `receive` function exists to expect
     * them. This function doesn't handle complex spaces in messages, and so the
     * `execf` function exists and uses hiredis's formatting instead.
     *
     * TODO: Move to IoResult using context.err
     */
    pub fn command(&self, command: &str) -> Option<Reply> {
        command.with_c_str(|v| {
            unsafe {
                /* This is the library call, returns (void*)0 on failure. */
                let result = api::redisCommand(self.context, v);

                /* Fail if the command errored for some reason. */
                if result == 0 as *const ::libc::c_void {
                    return None;
                }

                /* Otherwise cast the pointer to the actual struct type being
                 * returned and store it to be returned. */
                Some(Reply::new(result as *const api::Reply))
            }
        })
    }

    /**
     * Appends a command to the output buffer, allowing for pipelining.
     *
     * TODO: This needs to return a status code.
     */
    pub fn append_command(&self, command: &str) {
        command.with_c_str(|v| {
            unsafe {
                api::redisAppendCommand(self.context, v);
            }
        });
    }

    /**
     * Attempts to read a message from the input buffer. Blocking in this
     * context depends on how the connection was created.
     */
    pub fn receive(&self) -> Option<Reply> {
        unsafe {
            let reply: api::Reply = std::mem::uninitialized();
            let result            = api::redisGetReply(self.context, transmute(&reply));

            Some(Reply::new(result as *const api::Reply))
        }
    }
}

impl Drop for Redis {
    /**
     * When a Redis instance goes out of scope, the connection needs to be
     * closed. Redis has a function for this that both closes the connection and
     * frees any resources used.
     */
    fn drop(&mut self) {
        unsafe {
            api::redisFree(self.context)
        }
    }
}
<|endoftext|>