<commit_before>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::CARD_SIZE;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{in_kilo, on_different_cards, start_of_card};
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::{offset_of_array_data, Obj};
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: ForwardTable,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: ForwardTable::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let garbage = init_size - new_size;
            let garbage_ratio = (garbage as f64 / init_size as f64) * 100f64;

            println!(
                "GC: Full GC ({:.2} ms, {:.1}K->{:.1}K size, {:.1}K/{:.0}% garbage)",
                in_ms(dur),
                in_kilo(init_size),
                in_kilo(new_size),
                in_kilo(garbage),
                garbage_ratio
            );
        });
    }

    fn heap_size(&self) -> usize {
        self.young.used_region().size() + self.old.used_region().size()
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();
        let mut live_objects = 0;

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                if !self.is_marked_addr(root_ptr) {
                    marking_stack.push(root_ptr);
                    self.mark(root_ptr);
                    live_objects += 1;
                }
            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                        live_objects += 1;
                    }
                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }

        self.fwd_table.reserve_capacity(live_objects);
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.forward_to(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, address, _| {
            if full.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if !field_addr.is_null() && !full.perm_space.contains(field_addr) {
                        let fwd_addr = full.fwd_table.forward_address(field_addr);
                        field.set(fwd_addr.to_mut_ptr());

                        if full.young.contains(fwd_addr) {
                            young_refs = true;
                        }
                    }
                });

                if young_refs {
                    full.fwd_table.set_young_refs(address);
                }
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr) {
                let fwd_addr = self.fwd_table.forward_address(root_ptr);
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let dest = full.fwd_table.forward_address(address);
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = full.fwd_table.has_young_refs(address);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(dest, next_dest, object.is_array_ref());
                    full.update_card(dest, &mut young_refs);
                }

                last_dest = next_dest;
            }
        });

        if !last_dest.is_null() && !start_of_card(last_dest) && self.old.contains(last_dest) {
            self.update_card(last_dest, &mut young_refs);
        }

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;
        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.valid_top(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.valid_top(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        assert!(self.old_top.is_null());
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, last: Address, addr: Address, array_ref: bool) {
        let last_card = self.old.card_from_address(last);

        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / mem::ptr_width_usize();

        let card = self.old.card_from_address(addr);

        if array_ref {
            let last_card_end = self.old.address_from_card(last_card).offset(CARD_SIZE);
            let loop_start;

            if last.offset(offset_of_array_data() as usize) > last_card_end {
                let diff_words = last_card_end.offset_from(last) / mem::ptr_width_usize();
                self.crossing_map.set_array_start((last_card.to_usize()+1).into(), diff_words);

                loop_start = last_card.to_usize() + 2;
            } else {
                loop_start = last_card.to_usize() + 1;
            }

            let refs_per_card = CARD_SIZE / mem::ptr_width_usize();

            for i in loop_start .. card.to_usize() {
                self.crossing_map.set_references_at_start(i.into(), refs_per_card);
            }

            if card.to_usize() >= loop_start {
                self.crossing_map.set_references_at_start(card, offset_words);
            }

        } else {
            for i in last_card.to_usize()+1 .. card.to_usize() {
                self.crossing_map.set_no_references(i.into());
            }

            self.crossing_map.set_first_object(card, offset_words);
        }
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap
            .is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe { *addr.to_ptr() }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}

struct ForwardTable {
    data: HashMap<Address, AddressWithYoungRefs>,
}

impl ForwardTable {
    fn new() -> ForwardTable {
        ForwardTable {
            data: HashMap::new(),
        }
    }

    fn reserve_capacity(&mut self, count: usize) {
        self.data.reserve(count);
    }

    fn forward_to(&mut self, addr: Address, fwd: Address) {
        self.data.insert(addr, AddressWithYoungRefs::new(fwd));
    }

    fn forward_address(&mut self, addr: Address) -> Address {
        self.data
            .get(&addr)
            .expect("no forward address found.")
            .address()
    }

    fn has_young_refs(&mut self, addr: Address) -> bool {
        self.data
            .get(&addr)
            .expect("no forward address found.")
            .has_young_refs()
    }

    fn set_young_refs(&mut self, addr: Address) {
        let value = self.data.get_mut(&addr).expect("no forward address found.");
        *value = value.set_young_refs();
    }
}

#[derive(Copy, Clone)]
struct AddressWithYoungRefs {
    data: usize,
}

impl AddressWithYoungRefs {
    fn new(addr: Address) -> AddressWithYoungRefs {
        AddressWithYoungRefs {
            data: addr.to_usize(),
        }
    }

    fn address(self) -> Address {
        (self.data & !1).into()
    }

    fn has_young_refs(self) -> bool {
        (self.data & 1) != 0
    }

    fn set_young_refs(self) -> AddressWithYoungRefs {
        AddressWithYoungRefs {
            data: self.data | 1,
        }
    }
}
<commit_msg>swiper: update card entry for array objects<commit_after>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::CARD_SIZE;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{in_kilo, on_different_cards, start_of_card};
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::{offset_of_array_data, Obj};
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: ForwardTable,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: ForwardTable::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let garbage = init_size - new_size;
            let garbage_ratio = (garbage as f64 / init_size as f64) * 100f64;

            println!(
                "GC: Full GC ({:.2} ms, {:.1}K->{:.1}K size, {:.1}K/{:.0}% garbage)",
                in_ms(dur),
                in_kilo(init_size),
                in_kilo(new_size),
                in_kilo(garbage),
                garbage_ratio
            );
        });
    }

    fn heap_size(&self) -> usize {
        self.young.used_region().size() + self.old.used_region().size()
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();
        let mut live_objects = 0;

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                if !self.is_marked_addr(root_ptr) {
                    marking_stack.push(root_ptr);
                    self.mark(root_ptr);
                    live_objects += 1;
                }
            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                        live_objects += 1;
                    }
                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }

        self.fwd_table.reserve_capacity(live_objects);
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.forward_to(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, address, _| {
            if full.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if !field_addr.is_null() && !full.perm_space.contains(field_addr) {
                        let fwd_addr = full.fwd_table.forward_address(field_addr);
                        field.set(fwd_addr.to_mut_ptr());

                        if full.young.contains(fwd_addr) {
                            young_refs = true;
                        }
                    }
                });

                if young_refs {
                    full.fwd_table.set_young_refs(address);
                }
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr) {
                let fwd_addr = self.fwd_table.forward_address(root_ptr);
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let dest = full.fwd_table.forward_address(address);
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = full.fwd_table.has_young_refs(address);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(dest, next_dest, object.is_array_ref());
                    full.update_card(dest, next_dest, &mut young_refs);
                }

                last_dest = next_dest;
            }
        });

        if !last_dest.is_null() && !start_of_card(last_dest) && self.old.contains(last_dest) {
            self.update_card(last_dest, last_dest, &mut young_refs);
        }

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;
        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.valid_top(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.valid_top(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        assert!(self.old_top.is_null());
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, last: Address, addr: Address, array_ref: bool) {
        let last_card = self.old.card_from_address(last);

        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / mem::ptr_width_usize();

        let card = self.old.card_from_address(addr);

        if array_ref {
            let last_card_end = self.old.address_from_card(last_card).offset(CARD_SIZE);
            let loop_start;

            if last.offset(offset_of_array_data() as usize) > last_card_end {
                let diff_words = last_card_end.offset_from(last) / mem::ptr_width_usize();
                self.crossing_map.set_array_start((last_card.to_usize()+1).into(), diff_words);

                loop_start = last_card.to_usize() + 2;
            } else {
                loop_start = last_card.to_usize() + 1;
            }

            let refs_per_card = CARD_SIZE / mem::ptr_width_usize();

            for i in loop_start .. card.to_usize() {
                self.crossing_map.set_references_at_start(i.into(), refs_per_card);
            }

            if card.to_usize() >= loop_start {
                self.crossing_map.set_references_at_start(card, offset_words);
            }

        } else {
            for i in last_card.to_usize()+1 .. card.to_usize() {
                self.crossing_map.set_no_references(i.into());
            }

            self.crossing_map.set_first_object(card, offset_words);
        }
    }

    fn update_card(&mut self, addr: Address, next: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);
        let next_card = self.old.card_from_address(next);

        let card_entry = if *young_refs {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        };
        self.card_table.set(card, card_entry);

        for i in card.to_usize()+1 .. next_card.to_usize() {
            self.card_table.set(i.into(), CardEntry::Clean);
        }

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap
            .is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe { *addr.to_ptr() }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}

struct ForwardTable {
    data: HashMap<Address, AddressWithYoungRefs>,
}

impl ForwardTable {
    fn new() -> ForwardTable {
        ForwardTable {
            data: HashMap::new(),
        }
    }

    fn reserve_capacity(&mut self, count: usize) {
        self.data.reserve(count);
    }

    fn forward_to(&mut self, addr: Address, fwd: Address) {
        self.data.insert(addr, AddressWithYoungRefs::new(fwd));
    }

    fn forward_address(&mut self, addr: Address) -> Address {
        self.data
            .get(&addr)
            .expect("no forward address found.")
            .address()
    }

    fn has_young_refs(&mut self, addr: Address) -> bool {
        self.data
            .get(&addr)
            .expect("no forward address found.")
            .has_young_refs()
    }

    fn set_young_refs(&mut self, addr: Address) {
        let value = self.data.get_mut(&addr).expect("no forward address found.");
        *value = value.set_young_refs();
    }
}

#[derive(Copy, Clone)]
struct AddressWithYoungRefs {
    data: usize,
}

impl AddressWithYoungRefs {
    fn new(addr: Address) -> AddressWithYoungRefs {
        AddressWithYoungRefs {
            data: addr.to_usize(),
        }
    }

    fn address(self) -> Address {
        (self.data & !1).into()
    }

    fn has_young_refs(self) -> bool {
        (self.data & 1) != 0
    }

    fn set_young_refs(self) -> AddressWithYoungRefs {
        AddressWithYoungRefs {
            data: self.data | 1,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2019, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use reqwest;
use serde_json::value::Value;
use std::path::Path;

/// Inserts POI into Elasticsearch and check results.
/// Prior to POI insertion, we need to insert contextual data:
/// - cosmogony (so that we get the admins),
/// - bano (so that we can attach the POI to an address)
pub fn poi2mimir_sample_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let out_dir = Path::new(env!("OUT_DIR"));

    let cosmogony2mimir = out_dir
        .join("../../../cosmogony2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &cosmogony2mimir,
        &[
            "--input=./tests/fixtures/cosmogony.json".into(),
            "--lang=fr".into(),
            "--lang=es".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let bano2mimir = out_dir.join("../../../bano2mimir").display().to_string();
    crate::launch_and_assert(
        &bano2mimir,
        &[
            "--input=./tests/fixtures/bano-three_cities.csv".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    // Now import some POI. We will assume this is a private dataset, so we pass
    // the private flag to poi2mimir.
    let poi2mimir = out_dir.join("../../../poi2mimir").display().to_string();
    crate::launch_and_assert(
        &poi2mimir,
        &[
            "--input=./tests/fixtures/poi/test.poi".into(),
            format!("--connection-string={}", es_wrapper.host()),
            "--dataset=mti".into(),
            "--private".into(),
        ],
        &es_wrapper,
    );

    // Now we'll make sure that the 'munin_poi_mti_{timestamp}' index is aliased by only one alias,
    // Namely 'munin_poi_mti'. So we'll get all the aliases.
    // For reference, aliases should look like
    //
    // {                                   |
    //   "munin_admin_fr_[timestamp]": {   |
    //     "aliases": {                    |
    //       "munin": {},                  |
    //       "munin_admin": {},            | ==> Added by cosmogony2mimir
    //       "munin_admin_fr": {},         |
    //       "munin_geo_data": {}          |
    //     }                               |
    //   },                              ==
    //   "munin_addr_fr_[timestamp]": {    |
    //     "aliases": {                    |
    //       "munin": {},                  |
    //       "munin_addr": {},             | ==> Added by bano2mimir
    //       "munin_addr_fr": {},          |
    //       "munin_geo_data": {}          |
    //     }                               |
    //   },                              ==
    //   "munin_poi_mti_[timestamp]": {    |
    //     "aliases": {                    |
    //       "munin_poi_mti": {}           | ==> Added by poi2mimir
    //     }                               |
    //   }                                 |
    // }
    let mut res = reqwest::get(&format!("{host}/_aliases", host = es_wrapper.host())).unwrap();
    assert_eq!(res.status(), reqwest::StatusCode::OK);

    let json: Value = res.json().unwrap();
    let raw_indexes = json.as_object().unwrap();

    let first_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    let raw_poi_index = first_indexes
        .iter()
        .find(|index| index.starts_with("munin_poi_mti"))
        .unwrap();

    // The result of raw_indexes[raw_poi_index] is an object that looks like:
    // Object({"aliases": Object({"munin_poi_mti": Object({})})})
    // So we turn it into a map, get the 'aliases' value,
    // turn the result into a map, and get the key (hopefully its unique).
    let poi_index_alias = raw_indexes
        .get(raw_poi_index)
        .and_then(|json| json.as_object())
        .and_then(|s| s.get("aliases"))
        .and_then(|json| json.as_object())
        .and_then(|s| s.keys().cloned().next())
        .unwrap_or_else(String::new);

    assert_eq!(poi_index_alias, "munin_poi_mti");

    // Now that we're sure we're hitting the munin_poi_mti index, count how many documents we have
    // in there. This should be the same number of POI as in the test.poi file we inserted.
    assert_eq!(es_wrapper.count("munin_poi_mti", "_type:poi"), 4);

    // Ok, now check that we can get a POI on that index
    let agence_du_four = es_wrapper
        .search_and_filter_on_index("munin_poi_mti", "label:Agence TCL Du Four", |place| {
            place.label().starts_with("Agence TCL Du Four à Chaux")
        })
        .next()
        .expect("Could not find Agence TCL Du Four");
    assert!(agence_du_four.is_poi());

    // We test that the POI that was close to an address has been 'attached' to that address,
    // and inherited its admin and address: (Note that the data have been manipulated to fit)
    assert_eq!(
        agence_du_four
            .admins()
            .iter()
            .filter(|adm| adm.is_city())
            .map(|adm| &adm.name)
            .collect::<Vec<_>>(),
        vec!["Livry-sur-Seine"]
    );

    // If the POI has a city admin, then its weight is that of the city (or at least != 0.0)
    assert_relative_eq!(
        agence_du_four.poi().unwrap().weight,
        0.0f64,
        epsilon = std::f64::EPSILON
    );

    // Make sure that that POI is not visible from the global index
    assert!(es_wrapper
        .search_and_filter("label:Agence TCL Du Four", |place| {
            place.label().starts_with("Agence TCL Du Four à Chaux")
        })
        .next()
        .is_none());
}
<commit_msg>Fix test where weight ne 0<commit_after>// Copyright © 2019, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use reqwest;
use serde_json::value::Value;
use std::path::Path;

/// Inserts POI into Elasticsearch and check results.
/// Prior to POI insertion, we need to insert contextual data:
/// - cosmogony (so that we get the admins),
/// - bano (so that we can attach the POI to an address)
pub fn poi2mimir_sample_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let out_dir = Path::new(env!("OUT_DIR"));

    let cosmogony2mimir = out_dir
        .join("../../../cosmogony2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &cosmogony2mimir,
        &[
            "--input=./tests/fixtures/cosmogony.json".into(),
            "--lang=fr".into(),
            "--lang=es".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let bano2mimir = out_dir.join("../../../bano2mimir").display().to_string();
    crate::launch_and_assert(
        &bano2mimir,
        &[
            "--input=./tests/fixtures/bano-three_cities.csv".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    // Now import some POI. We will assume this is a private dataset, so we pass
    // the private flag to poi2mimir.
    let poi2mimir = out_dir.join("../../../poi2mimir").display().to_string();
    crate::launch_and_assert(
        &poi2mimir,
        &[
            "--input=./tests/fixtures/poi/test.poi".into(),
            format!("--connection-string={}", es_wrapper.host()),
            "--dataset=mti".into(),
            "--private".into(),
        ],
        &es_wrapper,
    );

    // Now we'll make sure that the 'munin_poi_mti_{timestamp}' index is aliased by only one alias,
    // Namely 'munin_poi_mti'. So we'll get all the aliases.
    // For reference, aliases should look like
    //
    // {                                   |
    //   "munin_admin_fr_[timestamp]": {   |
    //     "aliases": {                    |
    //       "munin": {},                  |
    //       "munin_admin": {},            | ==> Added by cosmogony2mimir
    //       "munin_admin_fr": {},         |
    //       "munin_geo_data": {}          |
    //     }                               |
    //   },                              ==
    //   "munin_addr_fr_[timestamp]": {    |
    //     "aliases": {                    |
    //       "munin": {},                  |
    //       "munin_addr": {},             | ==> Added by bano2mimir
    //       "munin_addr_fr": {},          |
    //       "munin_geo_data": {}          |
    //     }                               |
    //   },                              ==
    //   "munin_poi_mti_[timestamp]": {    |
    //     "aliases": {                    |
    //       "munin_poi_mti": {}           | ==> Added by poi2mimir
    //     }                               |
    //   }                                 |
    // }
    let mut res = reqwest::get(&format!("{host}/_aliases", host = es_wrapper.host())).unwrap();
    assert_eq!(res.status(), reqwest::StatusCode::OK);

    let json: Value = res.json().unwrap();
    let raw_indexes = json.as_object().unwrap();

    let first_indexes: Vec<String> = raw_indexes.keys().cloned().collect();

    let raw_poi_index = first_indexes
        .iter()
        .find(|index| index.starts_with("munin_poi_mti"))
        .unwrap();

    // The result of raw_indexes[raw_poi_index] is an object that looks like:
    // Object({"aliases": Object({"munin_poi_mti": Object({})})})
    // So we turn it into a map, get the 'aliases' value,
    // turn the result into a map, and get the key (hopefully its unique).
    let poi_index_alias = raw_indexes
        .get(raw_poi_index)
        .and_then(|json| json.as_object())
        .and_then(|s| s.get("aliases"))
        .and_then(|json| json.as_object())
        .and_then(|s| s.keys().cloned().next())
        .unwrap_or_else(String::new);

    assert_eq!(poi_index_alias, "munin_poi_mti");

    // Now that we're sure we're hitting the munin_poi_mti index, count how many documents we have
    // in there. This should be the same number of POI as in the test.poi file we inserted.
    assert_eq!(es_wrapper.count("munin_poi_mti", "_type:poi"), 4);

    // Ok, now check that we can get a POI on that index
    let agence_du_four = es_wrapper
        .search_and_filter_on_index("munin_poi_mti", "label:Agence TCL Du Four", |place| {
            place.label().starts_with("Agence TCL Du Four à Chaux")
        })
        .next()
        .expect("Could not find Agence TCL Du Four");
    assert!(agence_du_four.is_poi());

    // We test that the POI that was close to an address has been 'attached' to that address,
    // and inherited its admin and address: (Note that the data have been manipulated to fit)
    assert_eq!(
        agence_du_four
            .admins()
            .iter()
            .filter(|adm| adm.is_city())
            .map(|adm| &adm.name)
            .collect::<Vec<_>>(),
        vec!["Livry-sur-Seine"]
    );

    // If the POI has a city admin, then its weight is that of the city (or at least != 0.0)
    assert_relative_ne!(
        agence_du_four.poi().unwrap().weight,
        0.0f64,
        epsilon = std::f64::EPSILON
    );

    // Make sure that that POI is not visible from the global index
    assert!(es_wrapper
        .search_and_filter("label:Agence TCL Du Four", |place| {
            place.label().starts_with("Agence TCL Du Four à Chaux")
        })
        .next()
        .is_none());
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex, MutexGuard};
use wayland_server::{Liveness, Resource};
use wayland_server::protocol::{wl_pointer, wl_surface};

// TODO: handle pointer surface role

struct PointerInternal {
    known_pointers: Vec<wl_pointer::WlPointer>,
    focus: Option<wl_surface::WlSurface>,
}

impl PointerInternal {
    fn new() -> PointerInternal {
        PointerInternal {
            known_pointers: Vec::new(),
            focus: None,
        }
    }

    fn with_focused_pointers<F>(&self, mut f: F)
    where
        F: FnMut(&wl_pointer::WlPointer, &wl_surface::WlSurface),
    {
        if let Some(ref focus) = self.focus {
            for ptr in &self.known_pointers {
                if ptr.same_client_as(focus) {
                    f(ptr, focus)
                }
            }
        }
    }
}

/// An handle to a keyboard handler
///
/// It can be cloned and all clones manipulate the same internal state. Clones
/// can also be sent across threads.
///
/// This handle gives you access to an interface to send pointer events to your
/// clients.
#[derive(Clone)]
pub struct PointerHandle {
    inner: Arc<Mutex<PointerInternal>>,
}

impl PointerHandle {
    pub(crate) fn new_pointer(&self, pointer: wl_pointer::WlPointer) {
        let mut guard = self.inner.lock().unwrap();
        guard.known_pointers.push(pointer);
    }

    /// Notify that the pointer moved
    ///
    /// You provide the new location of the pointer, in the form of:
    ///
    /// - `None` if the pointer is not on top of a client surface
    /// - `Some(surface, x, y)` if the pointer is focusing surface `surface`,
    ///   at location `(x, y)` relative to this surface
    ///
    /// This will internally take care of notifying the appropriate client objects
    /// of enter/motion/leave events.
    pub fn motion(&self, location: Option<(&wl_surface::WlSurface, f64, f64)>, serial: u32, time: u32) {
        let mut guard = self.inner.lock().unwrap();
        // do we leave a surface ?
        let mut leave = true;
        if let Some(ref focus) = guard.focus {
            if let Some((surface, _, _)) = location {
                if focus.equals(surface) {
                    leave = false;
                }
            }
        }
        if leave {
            guard.with_focused_pointers(|pointer, surface| {
                pointer.leave(serial, surface);
                if pointer.version() >= 5 {
                    pointer.frame();
                }
            });
            guard.focus = None;
        }

        // do we enter one ?
        if let Some((surface, x, y)) = location {
            if guard.focus.is_none() {
                guard.focus = surface.clone();
                guard.with_focused_pointers(|pointer, surface| {
                    pointer.enter(serial, surface, x, y);
                    if pointer.version() >= 5 {
                        pointer.frame();
                    }
                })
            } else {
                // we were on top of a surface and remained on it
                guard.with_focused_pointers(|pointer, _| {
                    pointer.motion(time, x, y);
                    if pointer.version() >= 5 {
                        pointer.frame();
                    }
                })
            }
        }
    }

    /// Notify that a button was pressed
    ///
    /// This will internally send the appropriate button event to the client
    /// objects matching with the currently focused surface.
    pub fn button(&self, button: u32, state: wl_pointer::ButtonState, serial: u32, time: u32) {
        let guard = self.inner.lock().unwrap();
        guard.with_focused_pointers(|pointer, _| {
            pointer.button(serial, time, button, state);
            if pointer.version() >= 5 {
                pointer.frame();
            }
        })
    }

    /// Start an axis frame
    ///
    /// A single frame will group multiple scroll events as if they happended in the same instance.
    /// Dropping the returned `PointerAxisHandle` will group the events together.
    pub fn axis<'a>(&'a self) -> PointerAxisHandle<'a> {
        PointerAxisHandle {
            inner: self.inner.lock().unwrap(),
        }
    }

    pub(crate) fn cleanup_old_pointers(&self) {
        let mut guard = self.inner.lock().unwrap();
        guard
            .known_pointers
            .retain(|p| p.status() != Liveness::Dead);
    }
}

/// A frame of pointer axis events.
///
/// Can be used with the builder pattern, e.g.:
/// ```ignore
/// pointer.axis()
///     .source(AxisSource::Wheel)
///     .discrete(Axis::Vertical, 6)
///     .value(Axis::Vertical, 30, time)
///     .stop(Axis::Vertical);
/// ```
pub struct PointerAxisHandle<'a> {
    inner: MutexGuard<'a, PointerInternal>,
}

impl<'a> PointerAxisHandle<'a> {
    /// Specify the source of the axis events
    ///
    /// This event is optional, if no source is known, you can ignore this call.
    /// Only one source event is allowed per frame.
    ///
    /// Using the `AxisSource::Finger` requires a stop event to be send,
    /// when the user lifts off the finger (not necessarily in the same frame).
    pub fn source(&mut self, source: wl_pointer::AxisSource) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.axis_source(source);
            }
        });
        self
    }

    /// Specify discrete scrolling steps additionally to the computed value.
    ///
    /// This event is optional and gives the client additional information about
    /// the nature of the axis event. E.g. a scroll wheel might issue separate steps,
    /// while a touchpad may never issue this event as it has no steps.
    pub fn discrete(&mut self, axis: wl_pointer::Axis, steps: i32) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.axis_discrete(axis, steps);
            }
        });
        self
    }

    /// The actual scroll value. This event is the only required one, but can also
    /// be send multiple times. The values off one frame will be accumulated by the client.
    pub fn value(&mut self, axis: wl_pointer::Axis, value: f64, time: u32) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            pointer.axis(time, axis, value);
        });
        self
    }

    /// Notification of stop of scrolling on an axis.
    ///
    /// This event is required for sources of the `AxisSource::Finger` type
    /// and otherwise optional.
    pub fn stop(&mut self, axis: wl_pointer::Axis, time: u32) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.axis_stop(time, axis);
            }
        });
        self
    }

    pub fn done(&mut self) {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.frame();
            }
        })
    }
}

pub(crate) fn create_pointer_handler() -> PointerHandle {
    PointerHandle {
        inner: Arc::new(Mutex::new(PointerInternal::new())),
    }
}
<commit_msg>Add missing documentation for former Drop call<commit_after>use std::sync::{Arc, Mutex, MutexGuard};
use wayland_server::{Liveness, Resource};
use wayland_server::protocol::{wl_pointer, wl_surface};

// TODO: handle pointer surface role

struct PointerInternal {
    known_pointers: Vec<wl_pointer::WlPointer>,
    focus: Option<wl_surface::WlSurface>,
}

impl PointerInternal {
    fn new() -> PointerInternal {
        PointerInternal {
            known_pointers: Vec::new(),
            focus: None,
        }
    }

    fn with_focused_pointers<F>(&self, mut f: F)
    where
        F: FnMut(&wl_pointer::WlPointer, &wl_surface::WlSurface),
    {
        if let Some(ref focus) = self.focus {
            for ptr in &self.known_pointers {
                if ptr.same_client_as(focus) {
                    f(ptr, focus)
                }
            }
        }
    }
}

/// An handle to a keyboard handler
///
/// It can be cloned and all clones manipulate the same internal state. Clones
/// can also be sent across threads.
///
/// This handle gives you access to an interface to send pointer events to your
/// clients.
#[derive(Clone)]
pub struct PointerHandle {
    inner: Arc<Mutex<PointerInternal>>,
}

impl PointerHandle {
    pub(crate) fn new_pointer(&self, pointer: wl_pointer::WlPointer) {
        let mut guard = self.inner.lock().unwrap();
        guard.known_pointers.push(pointer);
    }

    /// Notify that the pointer moved
    ///
    /// You provide the new location of the pointer, in the form of:
    ///
    /// - `None` if the pointer is not on top of a client surface
    /// - `Some(surface, x, y)` if the pointer is focusing surface `surface`,
    ///   at location `(x, y)` relative to this surface
    ///
    /// This will internally take care of notifying the appropriate client objects
    /// of enter/motion/leave events.
    pub fn motion(&self, location: Option<(&wl_surface::WlSurface, f64, f64)>, serial: u32, time: u32) {
        let mut guard = self.inner.lock().unwrap();
        // do we leave a surface ?
        let mut leave = true;
        if let Some(ref focus) = guard.focus {
            if let Some((surface, _, _)) = location {
                if focus.equals(surface) {
                    leave = false;
                }
            }
        }
        if leave {
            guard.with_focused_pointers(|pointer, surface| {
                pointer.leave(serial, surface);
                if pointer.version() >= 5 {
                    pointer.frame();
                }
            });
            guard.focus = None;
        }

        // do we enter one ?
        if let Some((surface, x, y)) = location {
            if guard.focus.is_none() {
                guard.focus = surface.clone();
                guard.with_focused_pointers(|pointer, surface| {
                    pointer.enter(serial, surface, x, y);
                    if pointer.version() >= 5 {
                        pointer.frame();
                    }
                })
            } else {
                // we were on top of a surface and remained on it
                guard.with_focused_pointers(|pointer, _| {
                    pointer.motion(time, x, y);
                    if pointer.version() >= 5 {
                        pointer.frame();
                    }
                })
            }
        }
    }

    /// Notify that a button was pressed
    ///
    /// This will internally send the appropriate button event to the client
    /// objects matching with the currently focused surface.
    pub fn button(&self, button: u32, state: wl_pointer::ButtonState, serial: u32, time: u32) {
        let guard = self.inner.lock().unwrap();
        guard.with_focused_pointers(|pointer, _| {
            pointer.button(serial, time, button, state);
            if pointer.version() >= 5 {
                pointer.frame();
            }
        })
    }

    /// Start an axis frame
    ///
    /// A single frame will group multiple scroll events as if they happended in the same instance.
    /// Dropping the returned `PointerAxisHandle` will group the events together.
    pub fn axis<'a>(&'a self) -> PointerAxisHandle<'a> {
        PointerAxisHandle {
            inner: self.inner.lock().unwrap(),
        }
    }

    pub(crate) fn cleanup_old_pointers(&self) {
        let mut guard = self.inner.lock().unwrap();
        guard
            .known_pointers
            .retain(|p| p.status() != Liveness::Dead);
    }
}

/// A frame of pointer axis events.
///
/// Can be used with the builder pattern, e.g.:
/// ```ignore
/// pointer.axis()
///     .source(AxisSource::Wheel)
///     .discrete(Axis::Vertical, 6)
///     .value(Axis::Vertical, 30, time)
///     .stop(Axis::Vertical);
/// ```
pub struct PointerAxisHandle<'a> {
    inner: MutexGuard<'a, PointerInternal>,
}

impl<'a> PointerAxisHandle<'a> {
    /// Specify the source of the axis events
    ///
    /// This event is optional, if no source is known, you can ignore this call.
    /// Only one source event is allowed per frame.
    ///
    /// Using the `AxisSource::Finger` requires a stop event to be send,
    /// when the user lifts off the finger (not necessarily in the same frame).
    pub fn source(&mut self, source: wl_pointer::AxisSource) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.axis_source(source);
            }
        });
        self
    }

    /// Specify discrete scrolling steps additionally to the computed value.
    ///
    /// This event is optional and gives the client additional information about
    /// the nature of the axis event. E.g. a scroll wheel might issue separate steps,
    /// while a touchpad may never issue this event as it has no steps.
    pub fn discrete(&mut self, axis: wl_pointer::Axis, steps: i32) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.axis_discrete(axis, steps);
            }
        });
        self
    }

    /// The actual scroll value. This event is the only required one, but can also
    /// be send multiple times. The values off one frame will be accumulated by the client.
    pub fn value(&mut self, axis: wl_pointer::Axis, value: f64, time: u32) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            pointer.axis(time, axis, value);
        });
        self
    }

    /// Notification of stop of scrolling on an axis.
    ///
    /// This event is required for sources of the `AxisSource::Finger` type
    /// and otherwise optional.
    pub fn stop(&mut self, axis: wl_pointer::Axis, time: u32) -> &mut Self {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.axis_stop(time, axis);
            }
        });
        self
    }

    /// Finish this event
    ///
    /// This will group all axis calls together.
    /// Note: They are already submitted to the client, obmitting this call just
    /// leaves room for additional events.
    pub fn done(&mut self) {
        self.inner.with_focused_pointers(|pointer, _| {
            if pointer.version() >= 5 {
                pointer.frame();
            }
        })
    }
}

pub(crate) fn create_pointer_handler() -> PointerHandle {
    PointerHandle {
        inner: Arc::new(Mutex::new(PointerInternal::new())),
    }
}
<|endoftext|>


<commit_before>use command_prelude::*;

use cargo::ops;

pub fn cli() -> App {
    subcommand("new")
        .about("Create a new cargo package at <path>")
        .arg(Arg::with_name("path").required(true))
        .arg_new_opts()
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let opts = args.new_options(config)?;
    ops::new(&opts, config)?;
    let path = args.value_of("path").unwrap();
    config
        .shell()
        .status("Created", format!("{} `{}` project", opts.kind, path))?;
    Ok(())
}
<commit_msg>fix project name<commit_after>use command_prelude::*;

use cargo::ops;

pub fn cli() -> App {
    subcommand("new")
        .about("Create a new cargo package at <path>")
        .arg(Arg::with_name("path").required(true))
        .arg_new_opts()
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let opts = args.new_options(config)?;

    ops::new(&opts, config)?;
    let path = args.value_of("path").unwrap();
    let project_name = if let Some(name) = args.value_of("name") {
        name
    } else {
        path
    };
    config
        .shell()
        .status("Created", format!("{} `{}` project", opts.kind, project_name))?;
    Ok(())
}
<|endoftext|>


<commit_before>use libc::{c_char, c_double, c_int, c_void, size_t};
use std::mem;

#[cfg(target_arch="x86_64")]
#[path="ucontext_x86_64.rs"]
mod ucontext;

// This almost certainly needs to be made specific to just x86 (and
// add cases for the other processors).
#[cfg(not(target_arch="x86_64"))]
#[path="ucontext_generic.rs"]
mod ucontext;

// These almost certainly need to be replaced with something that is
// target/platform specific.
mod sigset;
mod sigstack;

#[cfg(target_arch="x86_64")]
const UNW_TDEP_CURSOR_LEN: usize = 127;

#[cfg(target_arch="x86_64")]
type unw_word_t = usize;

#[repr(C)]
pub struct unw_cursor_t {
    opaque: [unw_word_t; UNW_TDEP_CURSOR_LEN],
}

type unw_context_t = ucontext::ucontext_t;
type unw_regnum_t = c_int;

#[cfg(target_arch="x86_64")]
type unw_fpreg_t = c_double;

#[cfg(target_arch="x86_64")]
#[repr(C)]
struct unw_tdep_proc_info_t {

}

#[repr(C)]
struct unw_proc_info_t {
    start_ip: unw_word_t,
    end_ip: unw_word_t,
    lsda: unw_word_t,
    handler: unw_word_t,
    gp: unw_word_t,
    flags: unw_word_t,
    format: c_int,
    unwind_info_size: c_int,
    unwind_info: *mut c_void,
    extra: unw_tdep_proc_info_t,
}

#[repr(C)]
enum unw_save_loc_type_t {
    UNW_SLT_NONE,
    UNW_SLT_MEMORY,
    UNW_SLT_REG,
}

#[repr(C)]
struct unw_save_loc_t {
    type_: unw_save_loc_type_t,
    u: unw_word_t, // should be union { unw_word_t, unw_regnum_t }
    extra: unw_tdep_save_loc_t,
}

#[cfg(target_arch="x86_64")]
#[repr(C)]
struct unw_tdep_save_loc_t {

}

#[link(name="unwind")]
#[link(name="unwind-x86_64")]
extern {
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_getcontext"]
    fn unw_getcontext(ucp: *mut unw_context_t) -> c_int;
    fn unw_init_local(c: *mut unw_cursor_t, ctxt: *mut unw_context_t);
    fn unw_step(cp: *mut unw_cursor_t);
    fn unw_get_reg(cp: *mut unw_cursor_t, reg: unw_regnum_t, valp: *mut unw_word_t);
    fn unw_get_fpreg(cp: *mut unw_cursor_t, reg: unw_regnum_t, valp: *mut unw_fpreg_t);
    fn unw_resume(cp: *mut unw_cursor_t);

    // I think the methods (and global) below are solely used for "remote
    // unwinding", which is not immediately relevant to me, so I need
    // not worry about finding definition for `struct unw_addr_space`.

    // static unw_local_addr_space: unw_addr_space_t;
    // fn unw_init_remote(c: *mut unw_cursor_t, as: unw_addr_space_t, arg: *mut c_void);
    // fn unw_create_addr_space(ap: *mut unw_accessors_t, byteorder: c_int);
    // fn unw_destroy_addr_space(as: unw_addr_space_t);
    // fn unw_get_accessors(as: unw_addr_space_t) -> *mut unw_accessors_t;
    // fn unw_flush_cache(as: unw_addr_space, lo: unw_word_t, hi: unw_word_t);
    // fn unw_set_caching_policy(as: unw_addr_space, policy: unw_caching_policy_t) -> c_int;

    fn unw_regname(regnum: unw_regnum_t) -> *const c_char;
    fn unw_get_proc_info(cp: *mut unw_cursor_t, pip: *mut unw_proc_info_t);
    fn unw_get_save_loc(cp: *mut unw_cursor_t, _int: c_int, loc: *mut unw_save_loc_t);
    fn unw_is_fpreg(r: unw_regnum_t) -> c_int;
    fn unw_is_signal_frame(cp: *mut unw_cursor_t) -> c_int;
    fn unw_get_proc_name(cp: *mut unw_cursor_t, bufp: *mut c_char, len: size_t, offp: *mut unw_word_t) -> c_int;

    // fn _U_dyn_register(di: *mut unw_dyn_info_t);
    // fn _U_dyn_cancel(di: *mut unw_dyn_info_t);
}

pub struct UnwindContext {
    repr: unw_context_t,
}

impl UnwindContext {
    pub fn new() -> UnwindContext {
        unsafe {
            let mut c = UnwindContext { repr: mem::uninitialized() };
            if 0 != unw_getcontext(&mut c.repr as *mut _) {
                panic!("got error from unw_getcontext");
            }
            return c;
        }
    }
}

<commit_msg>filled in a bunch of safe wrappers around `libunwind` API.<commit_after>use libc::{c_char, c_double, c_int, c_void, size_t};
use std::mem;
use std::ffi::CStr;

#[cfg(target_arch="x86_64")]
#[path="ucontext_x86_64.rs"]
mod ucontext;

// This almost certainly needs to be made specific to just x86 (and
// add cases for the other processors).
#[cfg(not(target_arch="x86_64"))]
#[path="ucontext_generic.rs"]
mod ucontext;

// These almost certainly need to be replaced with something that is
// target/platform specific.
mod sigset;
mod sigstack;

#[cfg(target_arch="x86_64")]
const UNW_TDEP_CURSOR_LEN: usize = 127;

#[cfg(target_arch="x86_64")]
type unw_word_t = usize;

#[repr(C)]
pub struct unw_cursor_t {
    opaque: [unw_word_t; UNW_TDEP_CURSOR_LEN],
}

type unw_context_t = ucontext::ucontext_t;
pub type unw_regnum_t = c_int;

#[cfg(target_arch="x86_64")]
type unw_fpreg_t = c_double;

#[cfg(target_arch="x86_64")]
#[repr(C)]
struct unw_tdep_proc_info_t {

}

#[repr(C)]
struct unw_proc_info_t {
    start_ip: unw_word_t,
    end_ip: unw_word_t,
    lsda: unw_word_t,
    handler: unw_word_t,
    gp: unw_word_t,
    flags: unw_word_t,
    format: c_int,
    unwind_info_size: c_int,
    unwind_info: *mut c_void,
    extra: unw_tdep_proc_info_t,
}

#[repr(C)]
enum unw_save_loc_type_t {
    UNW_SLT_NONE,
    UNW_SLT_MEMORY,
    UNW_SLT_REG,
}

#[repr(C)]
struct unw_save_loc_t {
    type_: unw_save_loc_type_t,
    u: unw_word_t, // should be union { unw_word_t, unw_regnum_t }
    extra: unw_tdep_save_loc_t,
}

#[cfg(target_arch="x86_64")]
#[repr(C)]
struct unw_tdep_save_loc_t {

}

#[link(name="unwind")]
#[link(name="unwind-x86_64")]
extern {
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_getcontext"]
    fn unw_getcontext(ucp: *mut unw_context_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_init_local"]
    fn unw_init_local(c: *mut unw_cursor_t, ctxt: *const unw_context_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_step"]
    fn unw_step(cp: *mut unw_cursor_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_get_reg"]
    fn unw_get_reg(cp: *const unw_cursor_t, reg: unw_regnum_t, valp: *mut unw_word_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_get_fpreg"]
    fn unw_get_fpreg(cp: *const unw_cursor_t, reg: unw_regnum_t, valp: *mut unw_fpreg_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_resume"]
    fn unw_resume(cp: *const unw_cursor_t) -> c_int;

    // I think the methods (and global) below are solely used for "remote
    // unwinding", which is not immediately relevant to me, so I need
    // not worry about finding definition for `struct unw_addr_space`.

    // static unw_local_addr_space: unw_addr_space_t;
    // fn unw_init_remote(c: *mut unw_cursor_t, as: unw_addr_space_t, arg: *mut c_void);
    // fn unw_create_addr_space(ap: *mut unw_accessors_t, byteorder: c_int);
    // fn unw_destroy_addr_space(as: unw_addr_space_t);
    // fn unw_get_accessors(as: unw_addr_space_t) -> *mut unw_accessors_t;
    // fn unw_flush_cache(as: unw_addr_space, lo: unw_word_t, hi: unw_word_t);
    // fn unw_set_caching_policy(as: unw_addr_space, policy: unw_caching_policy_t) -> c_int;

    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_regname"]
    fn unw_regname(regnum: unw_regnum_t) -> *const c_char;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_get_proc_name"]
    fn unw_get_proc_info(cp: *const unw_cursor_t, pip: *mut unw_proc_info_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_get_save_loc"]
    fn unw_get_save_loc(cp: *const unw_cursor_t, _int: c_int, loc: *mut unw_save_loc_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_is_fpreg"]
    fn unw_is_fpreg(r: unw_regnum_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_is_signal_frame"]
    fn unw_is_signal_frame(cp: *const unw_cursor_t) -> c_int;
    #[cfg(target_arch="x86_64")]
    #[link_name="_Ux86_64_get_proc_name"]
    fn unw_get_proc_name(cp: *const unw_cursor_t, bufp: *mut c_char, len: size_t, offp: *mut unw_word_t) -> c_int;

    // fn _U_dyn_register(di: *mut unw_dyn_info_t);
    // fn _U_dyn_cancel(di: *mut unw_dyn_info_t);
}

pub struct UnwindContext {
    repr: unw_context_t,
}

pub struct UnwindCursor {
    repr: unw_cursor_t,
}

#[repr(i32)]
#[derive(Debug)]
pub enum UnwindError {
    /// Unspecified (general) error
    Unspec = -1,
    /// Out of memory
    NoMem = -2,
    /// Bad register number
    BadReg = -3,
    /// Attempt to write read-only register
    ReadOnlyReg = -4,
    /// Stop Unwinding
    StopUnwind = -5,
    /// Invalid IP
    InvalidIP = -6,
    /// Bad Frame
    BadFrame = -9,
    /// Unsupported Operation or Bad Value
    Invalid = -10,
    /// Unwind Info has unsupported version
    BadVersion = -11,
    /// No Unwind Info found
    NoInfo = -12,
}

impl UnwindContext {
    pub fn new() -> UnwindContext {
        unsafe {
            let mut c = UnwindContext { repr: mem::uninitialized() };
            if 0 != unw_getcontext(&mut c.repr as *mut _) {
                panic!("got error from unw_getcontext");
            }
            return c;
        }
    }
    pub fn cursor(&self) -> UnwindCursor {
        unsafe {
            let mut c = UnwindCursor { repr: mem::uninitialized() };
            if 0 != unw_init_local(&mut c.repr as *mut _, &self.repr as *const _) {
                panic!("got error from unw_init_local");
            }
            return c;
        }
    }
}

macro_rules! match_err {
    ($val:ident, $($Variant:ident),*; $default:expr) => {
        match $val {
            $(x if x == UnwindError::$Variant as c_int => UnwindError::$Variant),*,
            _ => $default,
        }
    }
}

macro_rules! match_errs {
    ($val:ident, $default:expr) => {
        match_err!($val, Unspec, NoMem, BadReg, ReadOnlyReg, StopUnwind,
                   InvalidIP, BadFrame, Invalid, BadVersion, NoInfo;
                   $default)
    }
}

impl UnwindCursor {
    pub fn step(mut self) -> Result<Option<UnwindCursor>, UnwindError> {
        unsafe {
            let ret = unw_step(&mut self.repr as *mut _);
            match ret {
                0 => Ok(None),
                x if x > 0 => Ok(Some(self)),
                x => Err(match_errs!(x, panic!("got error from unw_step")))
            }
        }
    }

    pub fn get_reg(&self, reg: unw_regnum_t) -> Result<unw_word_t, UnwindError> {
        unsafe {
            let mut w: unw_word_t = mem::uninitialized();
            let ret = unw_get_reg(&self.repr as *const _, reg, &mut w as *mut _);
            match ret {
                0 => Ok(w),
                x => Err(match_errs!(x, panic!("got error from unw_get_reg"))),
            }
        }
    }

    pub fn get_fpreg(&self, reg: unw_regnum_t) -> Result<unw_fpreg_t, UnwindError> {
        unsafe {
            let mut w: unw_fpreg_t = mem::uninitialized();
            let ret = unw_get_fpreg(&self.repr as *const _, reg, &mut w as *mut _);
            match ret {
                0 => Ok(w),
                x => Err(match_errs!(x, panic!("got error from unw_get_fpreg"))),
            }
        }
    }

    pub fn resume(&self) -> Result<(), UnwindError> {
        unsafe {
            let ret = unw_resume(&self.repr as *const _);
            match ret {
                0 => Ok(()),
                x => Err(match_errs!(x, panic!("got error from unw_resume"))),
            }
        }
    }

    pub fn get_proc_info(&self) -> Result<unw_proc_info_t, UnwindError> {
        unsafe {
            let mut pip: unw_proc_info_t = mem::uninitialized();
            let ret = unw_get_proc_info(&self.repr as *const _, &mut pip as *mut _);
            match ret {
                0 => Ok(pip),
                x => Err(match_errs!(x, panic!("got error from get_proc_info"))),
            }
        }
    }

    pub fn get_save_loc(&self, i: c_int) -> Result<unw_save_loc_t, UnwindError> {
        unsafe {
            let mut loc: unw_save_loc_t = mem::uninitialized();
            let ret = unw_get_save_loc(&self.repr as *const _, i, &mut loc as *mut _);
            match ret {
                0 => Ok(loc),
                x => Err(match_errs!(x, panic!("got error from unw_get_save_loc"))),
            }
        }
    }

    pub fn is_signal_frame(&self) -> Result<bool, UnwindError> {
        unsafe {
            let ret = unw_is_signal_frame(&self.repr as *const _);
            match ret {
                0 => Ok(false),
                x if x > 0 => Ok(true),
                x => Err(match_errs!(x, panic!("got error from unw_is_signal_frame"))),
            }
        }
    }

    pub fn get_proc_name(&self, bufp: &mut Vec<c_char>) -> Result<unw_word_t, UnwindError> {
        unsafe {
            let mut off: unw_word_t = mem::uninitialized();
            let r: *const unw_cursor_t = &self.repr;
            let p: *mut c_char = bufp.as_mut_ptr();
            let c: size_t = bufp.capacity();
            let offp: *mut unw_word_t = &mut off as *mut unw_word_t;

            // The line below seems to cause an LLVM assert fail on my branch.

            // let ret: c_int = unw_get_proc_name(r, p, c, offp);
            // match ret {
            //     0 => Ok(off),
            //     x => Err(match_errs!(x, panic!("got error from unw_get_proc_name"))),
            // }
            unimplemented!()
        }
    }

}

pub fn is_fpreg(regnum: unw_regnum_t) -> bool {
    unsafe {
        0 != unw_is_fpreg(regnum)
    }
}

pub fn regname(regnum: unw_regnum_t) -> &'static CStr {
    unsafe {
        CStr::from_ptr(unw_regname(regnum))
    }
}
<|endoftext|>


<commit_before>extern crate mysql;
extern crate regex;

use mysql::conn::pool::MyPool;
use mysql::conn::pool::MyPooledConn;
use mysql::value::ToValue;
use mysql::conn::Stmt;

use std::process::{Command, Stdio};
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;

#[derive(Debug)]
pub enum DownloadError {
    ConsoleError(str),
    RadError,
    DMCAError,
    InternalError,
}
///Regex: [download]  13.4% of 275.27MiB at 525.36KiB/s ETA 07:52
///
///Downloads a video, updates the DB
///TODO: get the sql statements out of the class
///TODO: wrap errors
///Doesn't care about DMCAs, will emit errors on them
pub fn download_video(url: & str, quality: i32, qid: i64, folderFormat: & str, pool: MyPool) -> Result<bool,DownloadError> {
    println!("{:?}", url);
    let process = try!(run_process(&url, &folderFormat));
    let mut s = String::new(); //buffer prep
    let mut stdout = BufReader::new(process.stdout.unwrap());

    let mut conn = pool.get_conn().unwrap();
    let mut statement = prepare_progress_updater(&mut conn);
    let mut conn = pool.get_conn().unwrap();
    let re = create_regex(&r"\d+\.\d%");

    let i = 0;

    set_query_code(&mut conn, &1, &qid);

    for line in &mut stdout.lines(){
        match line{
            Err(why) => panic!("couldn't read cmd stdout: {}", Error::description(&why)),
            Ok(text) => {
                    println!("Out: {}",text);
                    match re.find(&text) {
                        Some(s) => { println!("Match at {}", s.0);
                                    println!("{}", &text[s.0..s.1]); // ONLY with ASCII chars makeable!
                                    update_progress(&mut statement, &text[s.0..s.1].to_string(), &qid);
                                },
                        None => println!("Detected no % match."),
                    }
                    //if re.is_match(&text) {println!("Match: {:?}", text);}
                },
        }
    }

    update_progress(&mut statement, &"Finished".to_string(), &qid);
    set_query_code(&mut conn, &3, &qid);

    Ok(true)
}

fn run_process(url: str, folderFormat: str) -> Result<Command,DownloadError> {
	match Command::new("youtube-dl")
                                .arg("--newline")
                                .arg(format!("-o {}",folderFormat))
                                .arg(url)
                                .stdin(Stdio::null())
                                .stdout(Stdio::piped())
                                .spawn() {
        Err(why) => Err(DownloadError::ConsoleError(Error::description(&why))),
        Ok(process) => Ok(process),
    }
}

fn create_regex(expression: & str) -> regex::Regex {
    match regex::Regex::new(expression) {
        Ok(re) => re,
        Err(err) => panic!("regex {}", err),
    }
}

// MyPooledConn does only live when MyOpts is alive -> lifetime needs to be declared
fn prepare_progress_updater<'a>(conn: &'a mut MyPooledConn) -> Stmt<'a> {
    conn.prepare("UPDATE querydetails SET status = ? WHERE qid = ?").unwrap()
}

fn set_query_code<'a>(conn: &'a mut MyPooledConn, code: &i8, qid: &i64){
    let mut stmt = conn.prepare("UPDATE querydetails SET code = ? WHERE qid = ?").unwrap();
    stmt.execute(&[code,qid]);
}

///updater called from the stdout progress
fn update_progress(stmt: &mut Stmt, progress: &String, qid: &i64){
    stmt.execute(&[progress,qid]);
}<commit_msg>now I need prob. to turn Error::description(&why) into own / double(l75)<commit_after>extern crate mysql;
extern crate regex;

use mysql::conn::pool::MyPool;
use mysql::conn::pool::MyPooledConn;
use mysql::value::ToValue;
use mysql::conn::Stmt;

use std::process::{Command, Stdio};
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::process::Child;

#[derive(Debug)]
pub enum DownloadError<'a>{
    ConsoleError(&'a str),
    RadError,
    DMCAError,
    InternalError,
}
///Regex: [download]  13.4% of 275.27MiB at 525.36KiB/s ETA 07:52
///
///Downloads a video, updates the DB
///TODO: get the sql statements out of the class
///TODO: wrap errors
///Doesn't care about DMCAs, will emit errors on them
pub fn download_video<'a>(url: & str, quality: i32, qid: i64, folderFormat: & str, pool: MyPool) -> Result<bool,DownloadError<'a>> {
    println!("{:?}", url);
    let process = try!(run_process(url, folderFormat));
    let mut s = String::new(); //buffer prep
    let mut stdout = BufReader::new(process.stdout.unwrap());

    let mut conn = pool.get_conn().unwrap();
    let mut statement = prepare_progress_updater(&mut conn);
    let mut conn = pool.get_conn().unwrap();
    let re = create_regex(&r"\d+\.\d%");

    let i = 0;

    set_query_code(&mut conn, &1, &qid);

    for line in &mut stdout.lines(){
        match line{
            Err(why) => panic!("couldn't read cmd stdout: {}", Error::description(&why)),
            Ok(text) => {
                    println!("Out: {}",text);
                    match re.find(&text) {
                        Some(s) => { println!("Match at {}", s.0);
                                    println!("{}", &text[s.0..s.1]); // ONLY with ASCII chars makeable!
                                    update_progress(&mut statement, &text[s.0..s.1].to_string(), &qid);
                                },
                        None => println!("Detected no % match."),
                    }
                    //if re.is_match(&text) {println!("Match: {:?}", text);}
                },
        }
    }

    update_progress(&mut statement, &"Finished".to_string(), &qid);
    set_query_code(&mut conn, &3, &qid);

    Ok(true)
}

fn run_process<'a>(url: &str, folderFormat: &str) -> Result<Child,DownloadError<'a>> {
	match Command::new("youtube-dl")
                                .arg("--newline")
                                .arg(format!("-o {}",folderFormat))
                                .arg(url)
                                .stdin(Stdio::null())
                                .stdout(Stdio::piped())
                                .spawn() {
        Err(why) => Err(DownloadError::ConsoleError(Error::description(&why))),
        Ok(process) => Ok(process),
    }
}

fn create_regex(expression: & str) -> regex::Regex {
    match regex::Regex::new(expression) {
        Ok(re) => re,
        Err(err) => panic!("regex {}", err),
    }
}

// MyPooledConn does only live when MyOpts is alive -> lifetime needs to be declared
fn prepare_progress_updater<'a>(conn: &'a mut MyPooledConn) -> Stmt<'a> {
    conn.prepare("UPDATE querydetails SET status = ? WHERE qid = ?").unwrap()
}

fn set_query_code<'a>(conn: &'a mut MyPooledConn, code: &i8, qid: &i64){
    let mut stmt = conn.prepare("UPDATE querydetails SET code = ? WHERE qid = ?").unwrap();
    stmt.execute(&[code,qid]);
}

///updater called from the stdout progress
fn update_progress(stmt: &mut Stmt, progress: &String, qid: &i64){
    stmt.execute(&[progress,qid]);
}<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities related to LSP text document syncing
#![allow(dead_code)]

use crate::{
    lsp::{DidChangeTextDocumentParams, DidOpenTextDocumentParams, TextDocumentItem, Url},
    lsp_runtime_error::LSPRuntimeResult,
    server::LSPState,
};

use common::PerfLogger;
use graphql_syntax::GraphQLSource;
use lsp_types::notification::{
    DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument, Notification,
};

pub type GraphQLTextDocumentCache = std::collections::HashMap<Url, Vec<GraphQLSource>>;

pub(crate) fn on_did_open_text_document<TPerfLogger: PerfLogger + 'static>(
    lsp_state: &mut LSPState<TPerfLogger>,
    params: <DidOpenTextDocument as Notification>::Params,
) -> LSPRuntimeResult<()> {
    let DidOpenTextDocumentParams { text_document } = params;
    let TextDocumentItem { text, uri, .. } = text_document;

    // First we check to see if this document has any GraphQL documents.
    let graphql_sources = match extract_graphql_sources(&text) {
        Some(sources) => sources,
        // Exit early if there are no sources
        None => return Ok(()),
    };

    // Track the GraphQL sources for this document
    lsp_state.insert_synced_sources(uri, graphql_sources);

    Ok(())
}

pub(crate) fn on_did_close_text_document<TPerfLogger: PerfLogger + 'static>(
    lsp_state: &mut LSPState<TPerfLogger>,
    params: <DidCloseTextDocument as Notification>::Params,
) -> LSPRuntimeResult<()> {
    let uri = params.text_document.uri;
    lsp_state.remove_synced_sources(&uri);
    Ok(())
}

pub(crate) fn on_did_change_text_document<TPerfLogger: PerfLogger + 'static>(
    lsp_state: &mut LSPState<TPerfLogger>,
    params: <DidChangeTextDocument as Notification>::Params,
) -> LSPRuntimeResult<()> {
    let DidChangeTextDocumentParams {
        content_changes,
        text_document,
    } = params;
    let uri = text_document.uri;

    // We do full text document syncing, so the new text will be in the first content change event.
    let content_change = content_changes
        .first()
        .expect("content_changes should always be non-empty");

    // First we check to see if this document has any GraphQL documents.
    let graphql_sources = match extract_graphql_sources(&content_change.text) {
        Some(sources) => sources,
        // Remove the item from the cache and exit early if there are no longer any sources
        None => {
            lsp_state.remove_synced_sources(&uri);
            return Ok(());
        }
    };

    // Update the GraphQL sources for this document
    lsp_state.insert_synced_sources(uri, graphql_sources);
    Ok(())
}

/// Returns a set of *non-empty* GraphQL sources if they exist in a file. Returns `None`
/// if extracting fails or there are no GraphQL chunks in the file.
fn extract_graphql_sources(source: &str) -> Option<Vec<GraphQLSource>> {
    match extract_graphql::parse_chunks(source) {
        Ok(chunks) => {
            if chunks.is_empty() {
                None
            } else {
                Some(chunks)
            }
        }
        // TODO T80565215 handle these errors
        Err(_) => None,
    }
}
<commit_msg>Get rid of some dead code<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities related to LSP text document syncing

use crate::{
    lsp::{DidChangeTextDocumentParams, DidOpenTextDocumentParams, TextDocumentItem},
    lsp_runtime_error::LSPRuntimeResult,
    server::LSPState,
};

use common::PerfLogger;
use graphql_syntax::GraphQLSource;
use lsp_types::notification::{
    DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument, Notification,
};

pub(crate) fn on_did_open_text_document<TPerfLogger: PerfLogger + 'static>(
    lsp_state: &mut LSPState<TPerfLogger>,
    params: <DidOpenTextDocument as Notification>::Params,
) -> LSPRuntimeResult<()> {
    let DidOpenTextDocumentParams { text_document } = params;
    let TextDocumentItem { text, uri, .. } = text_document;

    // First we check to see if this document has any GraphQL documents.
    let graphql_sources = match extract_graphql_sources(&text) {
        Some(sources) => sources,
        // Exit early if there are no sources
        None => return Ok(()),
    };

    // Track the GraphQL sources for this document
    lsp_state.insert_synced_sources(uri, graphql_sources);

    Ok(())
}

pub(crate) fn on_did_close_text_document<TPerfLogger: PerfLogger + 'static>(
    lsp_state: &mut LSPState<TPerfLogger>,
    params: <DidCloseTextDocument as Notification>::Params,
) -> LSPRuntimeResult<()> {
    let uri = params.text_document.uri;
    lsp_state.remove_synced_sources(&uri);
    Ok(())
}

pub(crate) fn on_did_change_text_document<TPerfLogger: PerfLogger + 'static>(
    lsp_state: &mut LSPState<TPerfLogger>,
    params: <DidChangeTextDocument as Notification>::Params,
) -> LSPRuntimeResult<()> {
    let DidChangeTextDocumentParams {
        content_changes,
        text_document,
    } = params;
    let uri = text_document.uri;

    // We do full text document syncing, so the new text will be in the first content change event.
    let content_change = content_changes
        .first()
        .expect("content_changes should always be non-empty");

    // First we check to see if this document has any GraphQL documents.
    let graphql_sources = match extract_graphql_sources(&content_change.text) {
        Some(sources) => sources,
        // Remove the item from the cache and exit early if there are no longer any sources
        None => {
            lsp_state.remove_synced_sources(&uri);
            return Ok(());
        }
    };

    // Update the GraphQL sources for this document
    lsp_state.insert_synced_sources(uri, graphql_sources);
    Ok(())
}

/// Returns a set of *non-empty* GraphQL sources if they exist in a file. Returns `None`
/// if extracting fails or there are no GraphQL chunks in the file.
fn extract_graphql_sources(source: &str) -> Option<Vec<GraphQLSource>> {
    match extract_graphql::parse_chunks(source) {
        Ok(chunks) => {
            if chunks.is_empty() {
                None
            } else {
                Some(chunks)
            }
        }
        // TODO T80565215 handle these errors
        Err(_) => None,
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Default, Deserialize)]
pub struct SchemaDocumentationJsonSource {
    types: Vec<TypeDescription>,
}

impl SchemaDocumentationJsonSource {
    pub fn create_from_json_value(value: Value) -> Result<Self, String> {
        serde_json::from_value(value)
            .map_err(|err| format!("Unable to create SchemaDocumentationJsonSource: {}", err))
    }
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TypeDescription {
    pub name: String,
    pub description: Option<String>,
    pub fields: Option<Vec<FieldDescription>>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct FieldDescription {
    name: String,
    description: Option<String>,
    args: Option<Vec<ArgDescription>>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ArgDescription {
    name: String,
    description: Option<String>,
}

pub struct SchemaDocumentation {
    types: HashMap<String, TypeDescription>,
}

impl Default for SchemaDocumentation {
    fn default() -> Self {
        Self {
            types: Default::default(),
        }
    }
}

impl From<SchemaDocumentationJsonSource> for SchemaDocumentation {
    fn from(source: SchemaDocumentationJsonSource) -> Self {
        let mut type_name = HashMap::default();
        for type_ in source.types {
            let key = type_.name.clone();
            type_name.insert(key, type_);
        }

        SchemaDocumentation { types: type_name }
    }
}

impl SchemaDocumentation {
    fn get_field(&self, type_name: &str, field_name: &str) -> Option<&FieldDescription> {
        let type_ = self.types.get(type_name)?;
        for field in type_.fields.as_ref()? {
            if field.name == field_name {
                return Some(field);
            }
        }

        None
    }

    pub fn get_type_description(&self, type_name: &str) -> Option<&str> {
        let type_ = self.types.get(type_name)?;

        type_
            .description
            .as_ref()
            .map(|description| description.as_ref())
    }

    pub fn get_field_description(&self, type_name: &str, field_name: &str) -> Option<&str> {
        let field = self.get_field(type_name, field_name)?;

        field
            .description
            .as_ref()
            .map(|description| description.as_ref())
    }

    pub fn get_field_argument_description(
        &self,
        type_name: &str,
        field_name: &str,
        argument_name: &str,
    ) -> Option<&str> {
        let field = self.get_field(type_name, field_name)?;

        for arg in field.args.as_ref()? {
            if argument_name == arg.name {
                return arg
                    .description
                    .as_ref()
                    .map(|description| description.as_ref());
            }
        }

        None
    }
}

#[cfg(test)]
mod tests {
    use super::SchemaDocumentation;
    use super::SchemaDocumentationJsonSource;
    use serde_json::{json, Value};

    fn create_docs() -> SchemaDocumentation {
        let source_value: Value = json!({
            "types": [
                {
                    "name": "Node",
                    "description": "Object with ID",
                    "fields": [
                        {
                            "name": "id",
                            "description": "Object ID",
                            "args": [],
                        },
                    ],
                },
                {
                    "name": "NoDescriptionType",
                    "description": null,
                },
                {
                    "name": "User",
                    "description": "Object with ID",
                    "fields": [
                        {
                            "name": "id",
                            "description": "Object ID",
                            "args": [],
                        },
                        {
                            "name": "name",
                            "description": "User name",
                            "args": [{
                                "name": "show_fill_name",
                                "description": "Show user's full name",
                            }, {
                                "name": "translate_name",
                            }],
                        },

                    ],
                },
            ],
        });
        let source = SchemaDocumentationJsonSource::create_from_json_value(source_value).unwrap();
        SchemaDocumentation::from(source)
    }

    #[test]
    fn test_get_type_description() {
        let docs = create_docs();
        assert_eq!(docs.get_type_description("Node"), Some("Object with ID"));
    }
    #[test]
    fn test_get_type_description_unknown() {
        let docs = create_docs();
        assert_eq!(docs.get_type_description("UnknownType"), None);
    }
    #[test]
    fn test_get_type_description_none() {
        let docs = create_docs();
        assert_eq!(docs.get_type_description("NoDescriptionType"), None);
    }

    #[test]
    fn test_get_field_description() {
        let docs = create_docs();
        assert_eq!(docs.get_field_description("Node", "id"), Some("Object ID"));
    }

    #[test]
    fn test_get_field_description_unknown() {
        let docs = create_docs();
        assert_eq!(docs.get_field_description("Unknown", "id"), None);
    }

    #[test]
    fn test_get_field_description_none() {
        let docs = create_docs();
        assert_eq!(docs.get_field_description("Node", "name"), None);
    }

    #[test]
    fn test_get_arg_description() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "name", "show_fill_name"),
            Some("Show user's full name")
        );
    }

    #[test]
    fn test_get_arg_description_none() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "name", "translate_name"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_unknown_type() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("UnknownType", "name", "translate_name"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_unknown_filed() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "profile_picture", "scale"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_non_existing_arg() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("None", "id", "non_existing"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_unknown_agg() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "name", "unknown_arg"),
            None
        );
    }
}
<commit_msg>Make get_schema_documentation a method on a SchemaDocumentationLoader trait<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::{collections::HashMap, sync::Arc};

use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Default, Deserialize)]
pub struct SchemaDocumentationJsonSource {
    types: Vec<TypeDescription>,
}

impl SchemaDocumentationJsonSource {
    pub fn create_from_json_value(value: Value) -> Result<Self, String> {
        serde_json::from_value(value)
            .map_err(|err| format!("Unable to create SchemaDocumentationJsonSource: {}", err))
    }
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TypeDescription {
    pub name: String,
    pub description: Option<String>,
    pub fields: Option<Vec<FieldDescription>>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct FieldDescription {
    name: String,
    description: Option<String>,
    args: Option<Vec<ArgDescription>>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ArgDescription {
    name: String,
    description: Option<String>,
}

pub trait SchemaDocumentationLoader {
    fn get_schema_documentation(&self, schema_name: &str) -> Arc<SchemaDocumentation>;
}

pub struct SchemaDocumentation {
    types: HashMap<String, TypeDescription>,
}

impl Default for SchemaDocumentation {
    fn default() -> Self {
        Self {
            types: Default::default(),
        }
    }
}

impl From<SchemaDocumentationJsonSource> for SchemaDocumentation {
    fn from(source: SchemaDocumentationJsonSource) -> Self {
        let mut type_name = HashMap::default();
        for type_ in source.types {
            let key = type_.name.clone();
            type_name.insert(key, type_);
        }

        SchemaDocumentation { types: type_name }
    }
}

impl SchemaDocumentation {
    fn get_field(&self, type_name: &str, field_name: &str) -> Option<&FieldDescription> {
        let type_ = self.types.get(type_name)?;
        for field in type_.fields.as_ref()? {
            if field.name == field_name {
                return Some(field);
            }
        }

        None
    }

    pub fn get_type_description(&self, type_name: &str) -> Option<&str> {
        let type_ = self.types.get(type_name)?;

        type_
            .description
            .as_ref()
            .map(|description| description.as_ref())
    }

    pub fn get_field_description(&self, type_name: &str, field_name: &str) -> Option<&str> {
        let field = self.get_field(type_name, field_name)?;

        field
            .description
            .as_ref()
            .map(|description| description.as_ref())
    }

    pub fn get_field_argument_description(
        &self,
        type_name: &str,
        field_name: &str,
        argument_name: &str,
    ) -> Option<&str> {
        let field = self.get_field(type_name, field_name)?;

        for arg in field.args.as_ref()? {
            if argument_name == arg.name {
                return arg
                    .description
                    .as_ref()
                    .map(|description| description.as_ref());
            }
        }

        None
    }
}

#[cfg(test)]
mod tests {
    use super::SchemaDocumentation;
    use super::SchemaDocumentationJsonSource;
    use serde_json::{json, Value};

    fn create_docs() -> SchemaDocumentation {
        let source_value: Value = json!({
            "types": [
                {
                    "name": "Node",
                    "description": "Object with ID",
                    "fields": [
                        {
                            "name": "id",
                            "description": "Object ID",
                            "args": [],
                        },
                    ],
                },
                {
                    "name": "NoDescriptionType",
                    "description": null,
                },
                {
                    "name": "User",
                    "description": "Object with ID",
                    "fields": [
                        {
                            "name": "id",
                            "description": "Object ID",
                            "args": [],
                        },
                        {
                            "name": "name",
                            "description": "User name",
                            "args": [{
                                "name": "show_fill_name",
                                "description": "Show user's full name",
                            }, {
                                "name": "translate_name",
                            }],
                        },

                    ],
                },
            ],
        });
        let source = SchemaDocumentationJsonSource::create_from_json_value(source_value).unwrap();
        SchemaDocumentation::from(source)
    }

    #[test]
    fn test_get_type_description() {
        let docs = create_docs();
        assert_eq!(docs.get_type_description("Node"), Some("Object with ID"));
    }
    #[test]
    fn test_get_type_description_unknown() {
        let docs = create_docs();
        assert_eq!(docs.get_type_description("UnknownType"), None);
    }
    #[test]
    fn test_get_type_description_none() {
        let docs = create_docs();
        assert_eq!(docs.get_type_description("NoDescriptionType"), None);
    }

    #[test]
    fn test_get_field_description() {
        let docs = create_docs();
        assert_eq!(docs.get_field_description("Node", "id"), Some("Object ID"));
    }

    #[test]
    fn test_get_field_description_unknown() {
        let docs = create_docs();
        assert_eq!(docs.get_field_description("Unknown", "id"), None);
    }

    #[test]
    fn test_get_field_description_none() {
        let docs = create_docs();
        assert_eq!(docs.get_field_description("Node", "name"), None);
    }

    #[test]
    fn test_get_arg_description() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "name", "show_fill_name"),
            Some("Show user's full name")
        );
    }

    #[test]
    fn test_get_arg_description_none() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "name", "translate_name"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_unknown_type() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("UnknownType", "name", "translate_name"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_unknown_filed() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "profile_picture", "scale"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_non_existing_arg() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("None", "id", "non_existing"),
            None
        );
    }

    #[test]
    fn test_get_arg_description_unknown_agg() {
        let docs = create_docs();
        assert_eq!(
            docs.get_field_argument_description("User", "name", "unknown_arg"),
            None
        );
    }
}
<|endoftext|>