<commit_before>use std::cmp;

use ctxt::SemContext;

use gc::root::IndirectObj;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::in_kilo;
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::swiper::{CardIdx, Region, CARD_SIZE};
use gc::Address;

use mem;
use object::Obj;
use timer::{in_ms, Timer};

pub struct MinorCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    young: &'a YoungGen,
    old: &'a OldGen,
    large: &'a LargeSpace,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,

    free: Address,
    promotion_failed: bool,
    promoted_size: usize,
    young_from: Region,
}

impl<'a, 'ast> MinorCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        young: &'a YoungGen,
        old: &'a OldGen,
        large: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        rootset: &'a [IndirectObj],
    ) -> MinorCollector<'a, 'ast> {
        MinorCollector {
            ctxt: ctxt,
            young: young,
            old: old,
            large: large,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            free: Address::null(),
            promotion_failed: false,
            promoted_size: 0,
            young_from: young.from_space(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();
        let young_init_size = self.young.used_region().size();
        self.free = self.young.to_space().start;

        self.young.unprotect_to_space();

        self.visit_roots();
        self.copy_dirty_cards();
        self.visit_large_objects();
        self.visit_copied_objects();
        self.young.swap_spaces(self.free);

        self.young.protect_to_space();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let young_new_size = self.young.used_region().size();
            let garbage = young_init_size - young_new_size - self.promoted_size;
            let garbage_ratio = (garbage as f64 / young_init_size as f64) * 100f64;

            println!(
                "GC: Minor GC ({:.2} ms, {:.1}K->{:.1}K, young {:.1}K->{:.1}K, \
                 {:.1}K promoted, {:.1}K/{:.0}% garbage)",
                in_ms(dur),
                in_kilo(init_size),
                in_kilo(new_size),
                in_kilo(young_init_size),
                in_kilo(young_new_size),
                in_kilo(self.promoted_size),
                in_kilo(garbage),
                garbage_ratio
            );
        });
    }

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

    fn visit_roots(&mut self) {
        // detect all references from roots into young generation
        for &root in self.rootset {
            let root_ptr = root.get();

            if self.young.contains(Address::from_ptr(root_ptr)) {
                root.set(self.copy(root_ptr));
            }
        }
    }

    fn visit_large_objects(&mut self) {
        self.large.visit_objects(|addr| {
            let object = unsafe { &mut *addr.to_mut_ptr::<Obj>() };

            if object.is_array_ref() {
                self.visit_large_object_array(object, addr);
            } else {
                self.visit_large_object(object, addr);
            }
        })
    }

    fn visit_large_object_array(&mut self, object: &mut Obj, object_start: Address) {
        let object_end = object_start.offset(object.size() as usize);
        let (start_card_idx, end_card_idx) = self.card_table.card_indices(object_start, object_end);

        for card_idx in start_card_idx..end_card_idx {
            let card_idx = card_idx.into();

            if self.card_table.get(card_idx).is_clean() {
                continue;
            }

            let card_start = self.card_table.to_address(card_idx);
            let card_end = card_start.offset(CARD_SIZE);
            let end = cmp::min(card_end, object_end);

            let mut ref_to_young_gen = false;

            if card_idx.to_usize() == start_card_idx {
                self.copy_range(object_start, end, &mut ref_to_young_gen);
            } else {
                // all but the first card are full with references
                let refs = end.offset_from(card_start) / mem::ptr_width_usize();
                self.copy_refs(card_start, refs, &mut ref_to_young_gen);
            }

            self.update_card(card_idx, ref_to_young_gen);
        }
    }

    fn visit_large_object(&mut self, object: &mut Obj, object_start: Address) {
        if !self.card_table.is_dirty(object_start) {
            return;
        }

        object.visit_reference_fields(|field| {
            let field_ptr = field.get();

            if self.young.contains(Address::from_ptr(field_ptr)) {
                field.set(self.copy(field_ptr));
            }
        });
    }

    fn visit_copied_objects(&mut self) {
        let mut scan = self.young.to_space().start;

        // visit all fields in copied objects
        while scan < self.free {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_ptr = field.get();

                if self.young.contains(Address::from_ptr(field_ptr)) {
                    field.set(self.copy(field_ptr));
                }
            });

            scan = scan.offset(object.size());
        }
    }

    // copy all references from old- into young-generation.
    fn copy_dirty_cards(&mut self) {
        self.card_table.visit_dirty_in_old(self.old.free(), |card_idx| {
            let crossing_entry = self.crossing_map.get(card_idx);
            let card_start = self.card_table.to_address(card_idx);

            match crossing_entry {
                CrossingEntry::NoRefs => panic!("card dirty without any refs"),
                CrossingEntry::LeadingRefs(refs) => {
                    let mut ref_to_young_gen = false;

                    // copy references at start of card
                    let first_object =
                        self.copy_refs(card_start, refs as usize, &mut ref_to_young_gen);

                    // copy all objects from this card
                    self.copy_old_card(card_idx, first_object, ref_to_young_gen);
                }

                CrossingEntry::FirstObject(offset) => {
                    let ptr = card_start.offset(offset as usize * mem::ptr_width_usize());

                    // copy all objects from this card
                    self.copy_old_card(card_idx, ptr, false);
                }

                CrossingEntry::ArrayStart(offset) => {
                    assert!(offset == 1);
                    let ptr = card_start.to_usize() - (offset as usize * mem::ptr_width_usize());

                    // copy all objects from this card
                    self.copy_old_card(card_idx, ptr.into(), false);
                }
            }
        });
    }

    fn copy_refs(&mut self, mut ptr: Address, refs: usize, ref_to_young_gen: &mut bool) -> Address {
        for _ in 0..refs {
            let ind_ptr = IndirectObj::from_address(ptr);
            let dir_ptr = ind_ptr.get();

            if self.young_from.contains(Address::from_ptr(dir_ptr)) {
                let copied_obj = self.copy(dir_ptr);
                ind_ptr.set(copied_obj);

                if self.young.contains(Address::from_ptr(copied_obj)) {
                    *ref_to_young_gen = true;
                }
            }

            ptr = ptr.offset(mem::ptr_width_usize());
        }

        ptr
    }

    fn copy_old_card(
        &mut self,
        card: CardIdx,
        mut ptr: Address,
        mut ref_to_young_gen: bool,
    ) {
        let card_start = self.card_table.to_address(card);
        let card_end = card_start.offset(CARD_SIZE);

        let old_end: Address = self.old.free();
        let mut end = cmp::min(card_end, old_end);

        loop {
            ptr = self.copy_range(ptr, end, &mut ref_to_young_gen);

            // if we are in the last card of the old generation, promoted objects
            // will increase `end` towards `card_end`. Those newly promoted objects
            // need also be handled.
            if end == card_end {
                break;
            }

            let old_end = self.old.free();
            let next_end = cmp::min(card_end, old_end);

            if end != next_end {
                end = next_end;
            } else {
                break;
            }
        }

        self.update_card(card, ref_to_young_gen);
    }

    fn copy_range(
        &mut self,
        mut ptr: Address,
        end: Address,
        ref_to_young_gen: &mut bool,
    ) -> Address {
        while ptr < end {
            let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields_within(end, |field| {
                let field_ptr = field.get();

                if self.young_from.contains(Address::from_ptr(field_ptr)) {
                    let copied_obj = self.copy(field_ptr);
                    field.set(copied_obj);

                    // determine if copied object is still in young generation
                    if self.young.contains(Address::from_ptr(copied_obj)) {
                        *ref_to_young_gen = true;
                    }
                }
            });

            ptr = ptr.offset(object.size());
        }

        end
    }

    fn update_card(&mut self, card_idx: CardIdx, ref_to_young_gen: bool) {
        // if there are no references to the young generation in this card,
        // set the card to clean.
        if !ref_to_young_gen {
            self.card_table.set(card_idx, CardEntry::Clean);
        }
    }

    fn copy(&mut self, obj: *mut Obj) -> *mut Obj {
        let obj_addr = Address::from_ptr(obj);
        let obj = unsafe { &mut *obj };

        if let Some(fwd) = obj.header().forwarded() {
            return fwd.to_mut_ptr();
        }

        let obj_size = obj.size();
        debug_assert!(
            self.young_from.contains(obj_addr),
            "copy objects only from from-space."
        );

        // if object is old enough we copy it into the old generation
        if self.young.should_be_promoted(obj_addr) {
            let copy_addr = self.old.alloc(obj_size, obj.is_array_ref());

            // if there isn't enough space in old gen keep it in the
            // young generation for now
            if copy_addr.is_null() {
                self.promotion_failed = true;
            } else {
                self.promote_object(obj, copy_addr, obj_size);
                return copy_addr.to_mut_ptr();
            }
        }

        let copy_addr = self.free;
        self.free = copy_addr.offset(obj_size);

        obj.copy_to(copy_addr, obj_size);
        obj.header_mut().forward_to(copy_addr);

        copy_addr.to_mut_ptr()
    }

    fn promote_object(&mut self, obj: &mut Obj, copy_addr: Address, obj_size: usize) {
        obj.copy_to(copy_addr, obj_size);
        self.promoted_size += obj_size;

        // Promoted object can have references to the young generation.
        // Set the card table entry to dirty if this is the case.
        self.handle_promoted_object(copy_addr);

        obj.header_mut().forward_to(copy_addr);
    }

    fn handle_promoted_object(&mut self, addr: Address) {
        let card_idx = self.card_table.card_idx(addr);

        // card is already dirty, nothing left to do.
        if self.card_table.get(card_idx).is_dirty() {
            return;
        }

        let object: &mut Obj = unsafe { &mut *addr.to_mut_ptr() };
        let mut old_to_young_ref = false;

        object.visit_reference_fields(|field| {
            let field_ptr = field.get();

            if self.young.contains(Address::from_ptr(field_ptr)) {
                old_to_young_ref = true;
            }
        });

        if old_to_young_ref {
            self.card_table.set(card_idx, CardEntry::Dirty);
        }
    }

    pub fn promotion_failed(&self) -> bool {
        self.promotion_failed
    }
}
<commit_msg>swiper: time phases in minor GC<commit_after>use std::cmp;

use ctxt::SemContext;

use gc::root::IndirectObj;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::in_kilo;
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::swiper::{CardIdx, Region, CARD_SIZE};
use gc::Address;

use mem;
use object::Obj;
use timer::{in_ms, Timer};

pub struct MinorCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    young: &'a YoungGen,
    old: &'a OldGen,
    large: &'a LargeSpace,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,

    free: Address,
    promotion_failed: bool,
    promoted_size: usize,
    young_from: Region,
}

impl<'a, 'ast> MinorCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        young: &'a YoungGen,
        old: &'a OldGen,
        large: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        rootset: &'a [IndirectObj],
    ) -> MinorCollector<'a, 'ast> {
        MinorCollector {
            ctxt: ctxt,
            young: young,
            old: old,
            large: large,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            free: Address::null(),
            promotion_failed: false,
            promoted_size: 0,
            young_from: young.from_space(),
        }
    }

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

        let init_size = self.heap_size();
        let young_init_size = self.young.used_region().size();
        self.free = self.young.to_space().start;

        self.young.unprotect_to_space();

        let time_roots = Timer::ms(active, || {
            self.visit_roots();
        });

        let time_dirty_cards = Timer::ms(active, || {
            self.copy_dirty_cards();
            self.visit_large_objects();
        });

        let time_traverse = Timer::ms(active, || {
            self.visit_copied_objects();
        });

        self.young.swap_spaces(self.free);
        self.young.protect_to_space();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let young_new_size = self.young.used_region().size();
            let garbage = young_init_size - young_new_size - self.promoted_size;
            let garbage_ratio = (garbage as f64 / young_init_size as f64) * 100f64;

            println!(
                "GC: Minor GC ({:.2} ms, {:.1}K->{:.1}K, young {:.1}K->{:.1}K, \
                 {:.1}K promoted, {:.1}K/{:.0}% garbage); \
                 root={:.1}ms dirty_cards={:.1}ms traverse={:.1}ms",
                in_ms(dur),
                in_kilo(init_size),
                in_kilo(new_size),
                in_kilo(young_init_size),
                in_kilo(young_new_size),
                in_kilo(self.promoted_size),
                in_kilo(garbage),
                garbage_ratio,
                time_roots,
                time_dirty_cards,
                time_traverse,
            );
        });
    }

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

    fn visit_roots(&mut self) {
        // detect all references from roots into young generation
        for &root in self.rootset {
            let root_ptr = root.get();

            if self.young.contains(Address::from_ptr(root_ptr)) {
                root.set(self.copy(root_ptr));
            }
        }
    }

    fn visit_large_objects(&mut self) {
        self.large.visit_objects(|addr| {
            let object = unsafe { &mut *addr.to_mut_ptr::<Obj>() };

            if object.is_array_ref() {
                self.visit_large_object_array(object, addr);
            } else {
                self.visit_large_object(object, addr);
            }
        })
    }

    fn visit_large_object_array(&mut self, object: &mut Obj, object_start: Address) {
        let object_end = object_start.offset(object.size() as usize);
        let (start_card_idx, end_card_idx) = self.card_table.card_indices(object_start, object_end);

        for card_idx in start_card_idx..end_card_idx {
            let card_idx = card_idx.into();

            if self.card_table.get(card_idx).is_clean() {
                continue;
            }

            let card_start = self.card_table.to_address(card_idx);
            let card_end = card_start.offset(CARD_SIZE);
            let end = cmp::min(card_end, object_end);

            let mut ref_to_young_gen = false;

            if card_idx.to_usize() == start_card_idx {
                self.copy_range(object_start, end, &mut ref_to_young_gen);
            } else {
                // all but the first card are full with references
                let refs = end.offset_from(card_start) / mem::ptr_width_usize();
                self.copy_refs(card_start, refs, &mut ref_to_young_gen);
            }

            self.update_card(card_idx, ref_to_young_gen);
        }
    }

    fn visit_large_object(&mut self, object: &mut Obj, object_start: Address) {
        if !self.card_table.is_dirty(object_start) {
            return;
        }

        object.visit_reference_fields(|field| {
            let field_ptr = field.get();

            if self.young.contains(Address::from_ptr(field_ptr)) {
                field.set(self.copy(field_ptr));
            }
        });
    }

    fn visit_copied_objects(&mut self) {
        let mut scan = self.young.to_space().start;

        // visit all fields in copied objects
        while scan < self.free {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_ptr = field.get();

                if self.young.contains(Address::from_ptr(field_ptr)) {
                    field.set(self.copy(field_ptr));
                }
            });

            scan = scan.offset(object.size());
        }
    }

    // copy all references from old- into young-generation.
    fn copy_dirty_cards(&mut self) {
        self.card_table.visit_dirty_in_old(self.old.free(), |card_idx| {
            let crossing_entry = self.crossing_map.get(card_idx);
            let card_start = self.card_table.to_address(card_idx);

            match crossing_entry {
                CrossingEntry::NoRefs => panic!("card dirty without any refs"),
                CrossingEntry::LeadingRefs(refs) => {
                    let mut ref_to_young_gen = false;

                    // copy references at start of card
                    let first_object =
                        self.copy_refs(card_start, refs as usize, &mut ref_to_young_gen);

                    // copy all objects from this card
                    self.copy_old_card(card_idx, first_object, ref_to_young_gen);
                }

                CrossingEntry::FirstObject(offset) => {
                    let ptr = card_start.offset(offset as usize * mem::ptr_width_usize());

                    // copy all objects from this card
                    self.copy_old_card(card_idx, ptr, false);
                }

                CrossingEntry::ArrayStart(offset) => {
                    assert!(offset == 1);
                    let ptr = card_start.to_usize() - (offset as usize * mem::ptr_width_usize());

                    // copy all objects from this card
                    self.copy_old_card(card_idx, ptr.into(), false);
                }
            }
        });
    }

    fn copy_refs(&mut self, mut ptr: Address, refs: usize, ref_to_young_gen: &mut bool) -> Address {
        for _ in 0..refs {
            let ind_ptr = IndirectObj::from_address(ptr);
            let dir_ptr = ind_ptr.get();

            if self.young_from.contains(Address::from_ptr(dir_ptr)) {
                let copied_obj = self.copy(dir_ptr);
                ind_ptr.set(copied_obj);

                if self.young.contains(Address::from_ptr(copied_obj)) {
                    *ref_to_young_gen = true;
                }
            }

            ptr = ptr.offset(mem::ptr_width_usize());
        }

        ptr
    }

    fn copy_old_card(
        &mut self,
        card: CardIdx,
        mut ptr: Address,
        mut ref_to_young_gen: bool,
    ) {
        let card_start = self.card_table.to_address(card);
        let card_end = card_start.offset(CARD_SIZE);

        let old_end: Address = self.old.free();
        let mut end = cmp::min(card_end, old_end);

        loop {
            ptr = self.copy_range(ptr, end, &mut ref_to_young_gen);

            // if we are in the last card of the old generation, promoted objects
            // will increase `end` towards `card_end`. Those newly promoted objects
            // need also be handled.
            if end == card_end {
                break;
            }

            let old_end = self.old.free();
            let next_end = cmp::min(card_end, old_end);

            if end != next_end {
                end = next_end;
            } else {
                break;
            }
        }

        self.update_card(card, ref_to_young_gen);
    }

    fn copy_range(
        &mut self,
        mut ptr: Address,
        end: Address,
        ref_to_young_gen: &mut bool,
    ) -> Address {
        while ptr < end {
            let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields_within(end, |field| {
                let field_ptr = field.get();

                if self.young_from.contains(Address::from_ptr(field_ptr)) {
                    let copied_obj = self.copy(field_ptr);
                    field.set(copied_obj);

                    // determine if copied object is still in young generation
                    if self.young.contains(Address::from_ptr(copied_obj)) {
                        *ref_to_young_gen = true;
                    }
                }
            });

            ptr = ptr.offset(object.size());
        }

        end
    }

    fn update_card(&mut self, card_idx: CardIdx, ref_to_young_gen: bool) {
        // if there are no references to the young generation in this card,
        // set the card to clean.
        if !ref_to_young_gen {
            self.card_table.set(card_idx, CardEntry::Clean);
        }
    }

    fn copy(&mut self, obj: *mut Obj) -> *mut Obj {
        let obj_addr = Address::from_ptr(obj);
        let obj = unsafe { &mut *obj };

        if let Some(fwd) = obj.header().forwarded() {
            return fwd.to_mut_ptr();
        }

        let obj_size = obj.size();
        debug_assert!(
            self.young_from.contains(obj_addr),
            "copy objects only from from-space."
        );

        // if object is old enough we copy it into the old generation
        if self.young.should_be_promoted(obj_addr) {
            let copy_addr = self.old.alloc(obj_size, obj.is_array_ref());

            // if there isn't enough space in old gen keep it in the
            // young generation for now
            if copy_addr.is_null() {
                self.promotion_failed = true;
            } else {
                self.promote_object(obj, copy_addr, obj_size);
                return copy_addr.to_mut_ptr();
            }
        }

        let copy_addr = self.free;
        self.free = copy_addr.offset(obj_size);

        obj.copy_to(copy_addr, obj_size);
        obj.header_mut().forward_to(copy_addr);

        copy_addr.to_mut_ptr()
    }

    fn promote_object(&mut self, obj: &mut Obj, copy_addr: Address, obj_size: usize) {
        obj.copy_to(copy_addr, obj_size);
        self.promoted_size += obj_size;

        // Promoted object can have references to the young generation.
        // Set the card table entry to dirty if this is the case.
        self.handle_promoted_object(copy_addr);

        obj.header_mut().forward_to(copy_addr);
    }

    fn handle_promoted_object(&mut self, addr: Address) {
        let card_idx = self.card_table.card_idx(addr);

        // card is already dirty, nothing left to do.
        if self.card_table.get(card_idx).is_dirty() {
            return;
        }

        let object: &mut Obj = unsafe { &mut *addr.to_mut_ptr() };
        let mut old_to_young_ref = false;

        object.visit_reference_fields(|field| {
            let field_ptr = field.get();

            if self.young.contains(Address::from_ptr(field_ptr)) {
                old_to_young_ref = true;
            }
        });

        if old_to_young_ref {
            self.card_table.set(card_idx, CardEntry::Dirty);
        }
    }

    pub fn promotion_failed(&self) -> bool {
        self.promotion_failed
    }
}
<|endoftext|>


<commit_before>//! # Custom `derive` pretending to be functional procedural macros on Rust 1.15
//!
//! This crate enables creating function-like macros (invoked as `foo!(...)`)
//! with a procedural component,
//! based on both custom `derive` (a.k.a. *Macros 1.1*) and `macro_rules!`.
//!
//! This convoluted mechanism enables such macros to run on stable Rust 1.15,
//! even though functional procedural macros (a.k.a. *Macros 2.0*) are not available yet.
//!
//! A library defining such a macro needs two crates: a “normal” one, and a `proc-macro` one.
//! In the example below we’ll call them `libfoo` and `libfoo-macros`, respectively.
//!
//! # Credits
//!
//! The trick that makes this crate work
//! is based on an idea from [David Tolnay](https://github.com/dtolnay).
//! Many thanks!
//!
//! # Example
//!
//! As a simple example, we’re going to re-implement the `stringify!` macro.
//! This is useless since `stringify!` already exists in the standard library,
//! and a bit absurd since this crate uses `stringify!` internally.
//!
//! Nevertheless, it serves as a simple example to demonstrate the use of this crate.
//!
//! ## The `proc-macro` crate
//!
//! The minimal `Cargo.toml` file is typical for Macros 1.1:
//!
//! ```toml
//! [package]
//! name = "libfoo-macros"
//! version = "1.0.0"
//!
//! [lib]
//! proc-macro = true
//! ```
//!
//! In the code, we define the procedural part of our macro in a function.
//! This function will not be used directly by end users,
//! but it still needs to be re-exported to them
//! (because of limitations in `macro_rules!`).
//!
//! To avoid name collisions, we include a long and explicit prefix in the function’s name.
//!
//! The function takes a string containing arbitrary Rust tokens,
//! and returns a string that is parsed as *items*.
//! The returned string can contain constants, statics, functions, `impl`s, etc.,
//! but not expressions directly.
//!
//! ```rust
//! #[macro_use] extern crate procedural_masquerade;
//! extern crate proc_macro;
//!
//! define_proc_macros! {
//!     #[allow(non_snake_case)]
//!     pub fn foo_internal__stringify_const(input: &str) -> String {
//!         format!("const STRINGIFIED: &'static str = {:?};", input)
//!     }
//! }
//! ```
//!
//! A less trivial macro would probably use
//! the [`syn`](https://github.com/dtolnay/syn/) crate to parse its input
//! and the [`quote`](https://github.com/dtolnay/quote) crate to generate its output.
//!
//! ## The library crate
//!
//! ```toml
//! [package]
//! name = "libfoo"
//! version = "1.0.0"
//!
//! [dependencies]
//! libfoo-macros = {path = "./macros", version = "1.0"}
//! ```
//!
//! ```rust
//! #[macro_use] extern crate libfoo_macros;  // (1)
//!
//! pub use libfoo_macros::*;  // (2)
//!
//! define_invoke_proc_macro!(libfoo__invoke_proc_macro);  // (3)
//!
//! #[macro_export]
//! macro_rules! foo_stringify {  // (4)
//!     ( $( $tts: tt ) ) => {
//!         {  // (5)
//!             libfoo__invoke_proc_macro! {  // (6)
//!                 foo_internal__stringify_const!( $( $tts ) )  // (7)
//!             }
//!             STRINGIFIED  // (8)
//!         }
//!     }
//! }
//! ```
//!
//! Let’s go trough the numbered lines one by one:
//!
//! 1. `libfoo` depends on `libfoo-macros`, and imports its macros.
//! 2. Everything exported by `libfoo-macros` (which is one custom `derive`)
//!    is re-exported to users of `libfoo`.
//!    They’re not expected to use it directly,
//!    but expansion of the `foo_stringify` macro needs it.
//! 3. This macro invocation defines yet another macro, called `libfoo__invoke_proc_macro`,
//!    which is also exported.
//!    This indirection is necessary
//!    because re-exporting `macro_rules!` macros doesn’t work currently,
//!    and once again it is used by the expansion of `foo_stringify`.
//!    Again, we use a long prefix to avoid name collisions.
//! 4. Finally, we define the macro that we really want.
//!    This one has a name that users will use.
//! 5. The expansion of this macro will define some items,
//!    whose names are not hygienic in `macro_rules`.
//!    So we wrap everything in an extra `{…}` block to prevent these names for leaking.
//! 6. Here we use the macro defined in (3),
//!    which allows us to write something that look like invoking a functional procedural macro,
//!    but really uses a custom `derive`.
//!    This will define a type called `ProceduralMasqueradeDummyType`,
//!    as a placeholder to use `derive`.
//!    If `libfoo__invoke_proc_macro!` is to be used more than once,
//!    each use needs to be nested in another block
//!    so that the names of multiple dummy types don’t collide.
//! 7. In addition to the dummy type,
//!    the items returned by our procedural component are inserted here.
//!    (In this case the `STRINGIFIED` constant.)
//! 8. Finally, we write the expression that we want the macro to evaluate to.
//!    This expression can use parts of `foo_stringify`’s input,
//!    it can contain control-flow statements like `return` or `continue`,
//!    and of course refer to procedurally-defined items.
//!
//! This macro can be used in an expression context.
//! It expands to a block-expression that contains some items (as an implementation detail)
//! and ends with another expression.
//!
//! ## For users
//!
//! Users of `libfoo` don’t need to worry about any of these implementation details.
//! They can use the `foo_stringify` macro as if it were a simle `macro_rules` macro:
//!
//! ```rust
//! #[macro_use] extern crate libfoo;
//!
//! fn main() {
//!     do_something(foo_stringify!(1 + 2));
//! }
//!
//! fn do_something(_: &str) { /* ... */ }
//! ```
//!
//! # More
//!
//! To see a more complex example, look at
//! [`cssparser`’s `src/macros.rs`](https://github.com/servo/rust-cssparser/blob/master/src/macros.rs)
//! and
//! [`cssparser-macros`’s `macros/lib.rs`](https://github.com/servo/rust-cssparser/blob/master/macros/lib.rs).

/// This macro wraps `&str -> String` functions
/// in custom `derive` implementations with `#[proc_macro_derive]`.
///
/// See crate documentation for details.
#[macro_export]
macro_rules! define_proc_macros {
    (
        $(
            $( #[$attr:meta] )*
            pub fn $proc_macro_name: ident ($input: ident : &str) -> String
            $body: block
        )+
    ) => {
        $(
            $( #[$attr] )*
            #[proc_macro_derive($proc_macro_name)]
            pub fn $proc_macro_name(derive_input: ::proc_macro::TokenStream)
                                    -> ::proc_macro::TokenStream {
                fn wrapped($input: &str) -> String {
                    $body
                }

                // syn uses a huge amount of stack in debug mode.
                let derive_input_string = derive_input.to_string();
                let handle =
                    ::std::thread::Builder::new().stack_size(128 * 1024 * 1024).spawn(move || {
                        wrapped($crate::_extract_input(&derive_input_string))
                    }).unwrap();

                handle.join().unwrap().parse().unwrap()
            }
        )+
    }
}

/// Implementation detail of `define_proc_macros!`.
///
/// **This function is not part of the public API. It can change or be removed between any versions.**
#[doc(hidden)]
pub fn _extract_input(derive_input: &str) -> &str {
    let mut input = derive_input;

    for expected in &[
        "#[allow(unused)]",
        "enum",
        "ProceduralMasqueradeDummyType",
        "{",
        "Input",
        "=",
        "(0,",
        "stringify!",
        "(",
    ] {
        input = input.trim_start();
        assert!(
            input.starts_with(expected),
            "expected prefix {:?} not found in {:?}",
            expected,
            derive_input
        );
        input = &input[expected.len()..];
    }

    for expected in [")", ").0,", "}"].iter().rev() {
        input = input.trim_end();
        assert!(
            input.ends_with(expected),
            "expected suffix {:?} not found in {:?}",
            expected,
            derive_input
        );
        let end = input.len() - expected.len();
        input = &input[..end];
    }

    input
}

/// This macro expands to the definition of another macro (whose name is given as a parameter).
///
/// See crate documentation for details.
#[macro_export]
macro_rules! define_invoke_proc_macro {
    ($macro_name: ident) => {
        /// Implementation detail of other macros in this crate.
        #[doc(hidden)]
        #[macro_export]
        macro_rules! $macro_name {
                            ($proc_macro_name: ident ! $paren: tt) => {
                                #[derive($proc_macro_name)]
                                #[allow(unused)]
                                enum ProceduralMasqueradeDummyType {
                                    // The magic happens here.
                                    //
                                    // We use an `enum` with an explicit discriminant
                                    // because that is the only case where a type definition
                                    // can contain a (const) expression.
                                    //
                                    // `(0, "foo").0` evalutes to 0, with the `"foo"` part ignored.
                                    //
                                    // By the time the `#[proc_macro_derive]` function
                                    // implementing `#[derive($proc_macro_name)]` is called,
                                    // `$paren` has already been replaced with the input of this inner macro,
                                    // but `stringify!` has not been expanded yet.
                                    //
                                    // This how arbitrary tokens can be inserted
                                    // in the input to the `#[proc_macro_derive]` function.
                                    //
                                    // Later, `stringify!(...)` is expanded into a string literal
                                    // which is then ignored.
                                    // Using `stringify!` enables passing arbitrary tokens
                                    // rather than only what can be parsed as a const expression.
                                    Input = (0, stringify! $paren ).0
                                }
                            }
                        }
    };
}
<commit_msg>Rustfmt again?<commit_after>//! # Custom `derive` pretending to be functional procedural macros on Rust 1.15
//!
//! This crate enables creating function-like macros (invoked as `foo!(...)`)
//! with a procedural component,
//! based on both custom `derive` (a.k.a. *Macros 1.1*) and `macro_rules!`.
//!
//! This convoluted mechanism enables such macros to run on stable Rust 1.15,
//! even though functional procedural macros (a.k.a. *Macros 2.0*) are not available yet.
//!
//! A library defining such a macro needs two crates: a “normal” one, and a `proc-macro` one.
//! In the example below we’ll call them `libfoo` and `libfoo-macros`, respectively.
//!
//! # Credits
//!
//! The trick that makes this crate work
//! is based on an idea from [David Tolnay](https://github.com/dtolnay).
//! Many thanks!
//!
//! # Example
//!
//! As a simple example, we’re going to re-implement the `stringify!` macro.
//! This is useless since `stringify!` already exists in the standard library,
//! and a bit absurd since this crate uses `stringify!` internally.
//!
//! Nevertheless, it serves as a simple example to demonstrate the use of this crate.
//!
//! ## The `proc-macro` crate
//!
//! The minimal `Cargo.toml` file is typical for Macros 1.1:
//!
//! ```toml
//! [package]
//! name = "libfoo-macros"
//! version = "1.0.0"
//!
//! [lib]
//! proc-macro = true
//! ```
//!
//! In the code, we define the procedural part of our macro in a function.
//! This function will not be used directly by end users,
//! but it still needs to be re-exported to them
//! (because of limitations in `macro_rules!`).
//!
//! To avoid name collisions, we include a long and explicit prefix in the function’s name.
//!
//! The function takes a string containing arbitrary Rust tokens,
//! and returns a string that is parsed as *items*.
//! The returned string can contain constants, statics, functions, `impl`s, etc.,
//! but not expressions directly.
//!
//! ```rust
//! #[macro_use] extern crate procedural_masquerade;
//! extern crate proc_macro;
//!
//! define_proc_macros! {
//!     #[allow(non_snake_case)]
//!     pub fn foo_internal__stringify_const(input: &str) -> String {
//!         format!("const STRINGIFIED: &'static str = {:?};", input)
//!     }
//! }
//! ```
//!
//! A less trivial macro would probably use
//! the [`syn`](https://github.com/dtolnay/syn/) crate to parse its input
//! and the [`quote`](https://github.com/dtolnay/quote) crate to generate its output.
//!
//! ## The library crate
//!
//! ```toml
//! [package]
//! name = "libfoo"
//! version = "1.0.0"
//!
//! [dependencies]
//! libfoo-macros = {path = "./macros", version = "1.0"}
//! ```
//!
//! ```rust
//! #[macro_use] extern crate libfoo_macros;  // (1)
//!
//! pub use libfoo_macros::*;  // (2)
//!
//! define_invoke_proc_macro!(libfoo__invoke_proc_macro);  // (3)
//!
//! #[macro_export]
//! macro_rules! foo_stringify {  // (4)
//!     ( $( $tts: tt ) ) => {
//!         {  // (5)
//!             libfoo__invoke_proc_macro! {  // (6)
//!                 foo_internal__stringify_const!( $( $tts ) )  // (7)
//!             }
//!             STRINGIFIED  // (8)
//!         }
//!     }
//! }
//! ```
//!
//! Let’s go trough the numbered lines one by one:
//!
//! 1. `libfoo` depends on `libfoo-macros`, and imports its macros.
//! 2. Everything exported by `libfoo-macros` (which is one custom `derive`)
//!    is re-exported to users of `libfoo`.
//!    They’re not expected to use it directly,
//!    but expansion of the `foo_stringify` macro needs it.
//! 3. This macro invocation defines yet another macro, called `libfoo__invoke_proc_macro`,
//!    which is also exported.
//!    This indirection is necessary
//!    because re-exporting `macro_rules!` macros doesn’t work currently,
//!    and once again it is used by the expansion of `foo_stringify`.
//!    Again, we use a long prefix to avoid name collisions.
//! 4. Finally, we define the macro that we really want.
//!    This one has a name that users will use.
//! 5. The expansion of this macro will define some items,
//!    whose names are not hygienic in `macro_rules`.
//!    So we wrap everything in an extra `{…}` block to prevent these names for leaking.
//! 6. Here we use the macro defined in (3),
//!    which allows us to write something that look like invoking a functional procedural macro,
//!    but really uses a custom `derive`.
//!    This will define a type called `ProceduralMasqueradeDummyType`,
//!    as a placeholder to use `derive`.
//!    If `libfoo__invoke_proc_macro!` is to be used more than once,
//!    each use needs to be nested in another block
//!    so that the names of multiple dummy types don’t collide.
//! 7. In addition to the dummy type,
//!    the items returned by our procedural component are inserted here.
//!    (In this case the `STRINGIFIED` constant.)
//! 8. Finally, we write the expression that we want the macro to evaluate to.
//!    This expression can use parts of `foo_stringify`’s input,
//!    it can contain control-flow statements like `return` or `continue`,
//!    and of course refer to procedurally-defined items.
//!
//! This macro can be used in an expression context.
//! It expands to a block-expression that contains some items (as an implementation detail)
//! and ends with another expression.
//!
//! ## For users
//!
//! Users of `libfoo` don’t need to worry about any of these implementation details.
//! They can use the `foo_stringify` macro as if it were a simle `macro_rules` macro:
//!
//! ```rust
//! #[macro_use] extern crate libfoo;
//!
//! fn main() {
//!     do_something(foo_stringify!(1 + 2));
//! }
//!
//! fn do_something(_: &str) { /* ... */ }
//! ```
//!
//! # More
//!
//! To see a more complex example, look at
//! [`cssparser`’s `src/macros.rs`](https://github.com/servo/rust-cssparser/blob/master/src/macros.rs)
//! and
//! [`cssparser-macros`’s `macros/lib.rs`](https://github.com/servo/rust-cssparser/blob/master/macros/lib.rs).

/// This macro wraps `&str -> String` functions
/// in custom `derive` implementations with `#[proc_macro_derive]`.
///
/// See crate documentation for details.
#[macro_export]
macro_rules! define_proc_macros {
    (
        $(
            $( #[$attr:meta] )*
            pub fn $proc_macro_name: ident ($input: ident : &str) -> String
            $body: block
        )+
    ) => {
        $(
            $( #[$attr] )*
            #[proc_macro_derive($proc_macro_name)]
            pub fn $proc_macro_name(derive_input: ::proc_macro::TokenStream)
                                    -> ::proc_macro::TokenStream {
                fn wrapped($input: &str) -> String {
                    $body
                }

                // syn uses a huge amount of stack in debug mode.
                let derive_input_string = derive_input.to_string();
                let handle =
                    ::std::thread::Builder::new().stack_size(128 * 1024 * 1024).spawn(move || {
                        wrapped($crate::_extract_input(&derive_input_string))
                    }).unwrap();

                handle.join().unwrap().parse().unwrap()
            }
        )+
    }
}

/// Implementation detail of `define_proc_macros!`.
///
/// **This function is not part of the public API. It can change or be removed between any versions.**
#[doc(hidden)]
pub fn _extract_input(derive_input: &str) -> &str {
    let mut input = derive_input;

    for expected in &[
        "#[allow(unused)]",
        "enum",
        "ProceduralMasqueradeDummyType",
        "{",
        "Input",
        "=",
        "(0,",
        "stringify!",
        "(",
    ] {
        input = input.trim_start();
        assert!(
            input.starts_with(expected),
            "expected prefix {:?} not found in {:?}",
            expected,
            derive_input
        );
        input = &input[expected.len()..];
    }

    for expected in [")", ").0,", "}"].iter().rev() {
        input = input.trim_end();
        assert!(
            input.ends_with(expected),
            "expected suffix {:?} not found in {:?}",
            expected,
            derive_input
        );
        let end = input.len() - expected.len();
        input = &input[..end];
    }

    input
}

/// This macro expands to the definition of another macro (whose name is given as a parameter).
///
/// See crate documentation for details.
#[macro_export]
macro_rules! define_invoke_proc_macro {
    ($macro_name: ident) => {
        /// Implementation detail of other macros in this crate.
        #[doc(hidden)]
        #[macro_export]
        macro_rules! $macro_name {
                                    ($proc_macro_name: ident ! $paren: tt) => {
                                        #[derive($proc_macro_name)]
                                        #[allow(unused)]
                                        enum ProceduralMasqueradeDummyType {
                                            // The magic happens here.
                                            //
                                            // We use an `enum` with an explicit discriminant
                                            // because that is the only case where a type definition
                                            // can contain a (const) expression.
                                            //
                                            // `(0, "foo").0` evalutes to 0, with the `"foo"` part ignored.
                                            //
                                            // By the time the `#[proc_macro_derive]` function
                                            // implementing `#[derive($proc_macro_name)]` is called,
                                            // `$paren` has already been replaced with the input of this inner macro,
                                            // but `stringify!` has not been expanded yet.
                                            //
                                            // This how arbitrary tokens can be inserted
                                            // in the input to the `#[proc_macro_derive]` function.
                                            //
                                            // Later, `stringify!(...)` is expanded into a string literal
                                            // which is then ignored.
                                            // Using `stringify!` enables passing arbitrary tokens
                                            // rather than only what can be parsed as a const expression.
                                            Input = (0, stringify! $paren ).0
                                        }
                                    }
                                }
    };
}
<|endoftext|>


<commit_before>use crate::app::AppContextPointer;
use bufr_read::{BufrFile, Message};
use chrono::naive::NaiveDate;
use itertools::izip;
use metfor::{Celsius, HectoPascal, Kelvin, Knots, Meters, WindSpdDir};
use optional::Optioned;
use sounding_analysis::Analysis;
use sounding_base::{Sounding, StationInfo};
use sounding_bufkit::BufkitFile;
use std::{error::Error, iter::once, path::PathBuf};

pub fn load_file(path: &PathBuf, ac: &AppContextPointer) -> Result<(), Box<dyn Error>> {
    let extension: Option<String> = path
        .extension()
        .map(|ext| ext.to_string_lossy().to_string());
    let extension = extension.as_ref().map(|ext| ext.as_str());

    match extension {
        Some("buf") => load_bufkit(path, ac)?,
        Some("bufr") => load_bufr(path, ac)?,
        Some(_) => unreachable!(),
        None => unreachable!(),
    }

    if let Some(name) = path.file_name() {
        let mut src_name = "File: ".to_owned();
        src_name.push_str(&name.to_string_lossy());
        ac.set_source_description(Some(src_name));
    }

    Ok(())
}

fn load_bufkit(path: &PathBuf, ac: &AppContextPointer) -> Result<(), Box<dyn Error>> {
    let file = BufkitFile::load(path)?;
    let data = file.data()?;

    ac.load_data(&mut data.into_iter());
    Ok(())
}

fn load_bufr(path: &PathBuf, ac: &AppContextPointer) -> Result<(), Box<dyn Error>> {
    let mut file = BufrFile::new(&path.to_string_lossy())?;

    if let Some(Ok(msg)) = file.nth(0){
        let data = bufr_to_sounding(msg)?;
        ac.load_data(data);
    }

    Ok(())
}

fn bufr_to_sounding(msg: Message) -> Result<impl Iterator<Item = Analysis>, Box<dyn Error>> {
    let pressure_vals = msg.double_array("pressure")?;
    let pressure_vals = pressure_vals
        .iter()
        .map(|p| p.map_t(|p| p / 100.0).map_t(HectoPascal));

    let height = msg.double_array("nonCoordinateGeopotentialHeight")?;
    let height = height.iter().map(|v| v.map_t(Meters));

    let temperature = msg.double_array("airTemperature")?;
    let temperature = temperature
        .iter()
        .map(|t| t.map_t(|t| Celsius::from(Kelvin(t))));

    let dpt = msg.double_array("dewpointTemperature")?;
    let dpt = dpt
        .iter()
        .map(|dp| dp.map_t(|dp| Celsius::from(Kelvin(dp))));

    let wspeed = msg.double_array("windSpeed")?;
    let wdir = msg.double_array("windDirection")?;
    let wind = izip!(wdir, wspeed).map(|(d_opt, s_opt)| {
        d_opt.and_then(|d| {
            s_opt.map_t(|s| WindSpdDir {
                speed: Knots(s),
                direction: d,
            })
        })
    });

    let mut p: Vec<Optioned<HectoPascal>> = vec![];
    let mut h: Vec<Optioned<Meters>> = vec![];
    let mut t: Vec<Optioned<Celsius>> = vec![];
    let mut dp: Vec<Optioned<Celsius>> = vec![];
    let mut w: Vec<Optioned<WindSpdDir<Knots>>> = vec![];

    let mut p0 = HectoPascal(std::f64::MAX);
    let mut z0 = Meters(-std::f64::MAX);

    for (p1, h1, t1, dp1, w1) in izip!(pressure_vals, height, temperature, dpt, wind) {
        if let (Some(p_val), Some(z_val)) = (p1.into(), h1.into()) {
            if p_val < p0 && z_val > z0 {
                p.push(p1);
                h.push(h1);
                t.push(t1);
                dp.push(dp1);
                w.push(w1);

                p0 = p_val;
                z0 = z_val;
            }
        }
    }

    let latitude = msg
        .double("latitude")
        .ok()
        .and_then(|val| val.into_option());
    let longitude = msg
        .double("longitude")
        .ok()
        .and_then(|val| val.into_option());
    let elevation = msg
        .double("heightOfStationGroundAboveMeanSeaLevel")
        .ok()
        .and_then(|val| val.into_option())
        .map(Meters);
    let lat_lon = latitude.and_then(|lat| longitude.map(|lon| (lat, lon)));
    let stn = StationInfo::new_with_values(None, lat_lon, elevation);

    let year = msg.long("year").ok().and_then(|v| v.into_option());
    let month = msg.long("month").ok().and_then(|v| v.into_option());
    let day = msg.long("day").ok().and_then(|v| v.into_option());
    let hour = msg.long("hour").ok().and_then(|v| v.into_option());

    let vt = year
        .and_then(|y| month.map(|m| (y as i32, m as u32)))
        .and_then(|(y, m)| day.map(|d| (y, m, d as u32)))
        .and_then(|(y, m, d)| hour.map(|h| (y, m, d, h as u32)))
        .map(|(y, m, d, h)| NaiveDate::from_ymd(y, m, d).and_hms(h, 0, 0));

    let snd = Sounding::new()
        .with_station_info(stn)
        .with_valid_time(vt)
        .with_lead_time(0) // Lead time in hours for forecast soundings.
        .with_pressure_profile(p)
        .with_height_profile(h)
        .with_temperature_profile(t)
        .with_dew_point_profile(dp)
        .with_wind_profile(w);

    let anal = Analysis::new(snd);

    Ok(once(anal))
}
<commit_msg>Thinned bufr soundings to 1 sample per hPa<commit_after>use crate::app::AppContextPointer;
use bufr_read::{BufrFile, Message};
use chrono::naive::NaiveDate;
use itertools::izip;
use metfor::{Celsius, HectoPascal, Kelvin, Knots, Meters, WindSpdDir};
use optional::Optioned;
use sounding_analysis::Analysis;
use sounding_base::{Sounding, StationInfo};
use sounding_bufkit::BufkitFile;
use std::{error::Error, iter::once, path::PathBuf};

pub fn load_file(path: &PathBuf, ac: &AppContextPointer) -> Result<(), Box<dyn Error>> {
    let extension: Option<String> = path
        .extension()
        .map(|ext| ext.to_string_lossy().to_string());
    let extension = extension.as_ref().map(|ext| ext.as_str());

    match extension {
        Some("buf") => load_bufkit(path, ac)?,
        Some("bufr") => load_bufr(path, ac)?,
        Some(_) => unreachable!(),
        None => unreachable!(),
    }

    if let Some(name) = path.file_name() {
        let mut src_name = "File: ".to_owned();
        src_name.push_str(&name.to_string_lossy());
        ac.set_source_description(Some(src_name));
    }

    Ok(())
}

fn load_bufkit(path: &PathBuf, ac: &AppContextPointer) -> Result<(), Box<dyn Error>> {
    let file = BufkitFile::load(path)?;
    let data = file.data()?;

    ac.load_data(&mut data.into_iter());
    Ok(())
}

fn load_bufr(path: &PathBuf, ac: &AppContextPointer) -> Result<(), Box<dyn Error>> {
    let file = BufrFile::new(&path.to_string_lossy())?;

    let data: Vec<Analysis> = file
        .filter_map(|result| result.ok())
        .filter_map(|msg| bufr_to_sounding(msg).ok())
        .collect();
    ac.load_data(data.into_iter());

    Ok(())
}

fn bufr_to_sounding(msg: Message) -> Result<Analysis, Box<dyn Error>> {
    let pressure_vals = msg.double_array("pressure")?;
    let pressure_vals = pressure_vals
        .iter()
        .map(|p| p.map_t(|p| p / 100.0).map_t(HectoPascal));

    let height = msg.double_array("nonCoordinateGeopotentialHeight")?;
    let height = height.iter().map(|v| v.map_t(Meters));

    let temperature = msg.double_array("airTemperature")?;
    let temperature = temperature
        .iter()
        .map(|t| t.map_t(|t| Celsius::from(Kelvin(t))));

    let dpt = msg.double_array("dewpointTemperature")?;
    let dpt = dpt
        .iter()
        .map(|dp| dp.map_t(|dp| Celsius::from(Kelvin(dp))));

    let wspeed = msg.double_array("windSpeed")?;
    let wdir = msg.double_array("windDirection")?;
    let wind = izip!(wdir, wspeed).map(|(d_opt, s_opt)| {
        d_opt.and_then(|d| {
            s_opt.map_t(|s| WindSpdDir {
                speed: Knots(s),
                direction: d,
            })
        })
    });

    let mut p: Vec<Optioned<HectoPascal>> = vec![];
    let mut h: Vec<Optioned<Meters>> = vec![];
    let mut t: Vec<Optioned<Celsius>> = vec![];
    let mut dp: Vec<Optioned<Celsius>> = vec![];
    let mut w: Vec<Optioned<WindSpdDir<Knots>>> = vec![];

    let mut p0 = HectoPascal(std::f64::MAX);
    let mut z0 = Meters(-std::f64::MAX);

    for (p1, h1, t1, dp1, w1) in izip!(pressure_vals, height, temperature, dpt, wind) {
        if let (Some(p_val), Some(z_val)) = (p1.into(), h1.into()) {
            if p_val <= p0 - HectoPascal(1.0) && z_val > z0 {
                p.push(p1);
                h.push(h1);
                t.push(t1);
                dp.push(dp1);
                w.push(w1);

                p0 = p_val;
                z0 = z_val;
            }
        }
    }

    let latitude = msg
        .double("latitude")
        .ok()
        .and_then(|val| val.into_option());
    let longitude = msg
        .double("longitude")
        .ok()
        .and_then(|val| val.into_option());
    let elevation = msg
        .double("heightOfStationGroundAboveMeanSeaLevel")
        .ok()
        .and_then(|val| val.into_option())
        .map(Meters);
    let lat_lon = latitude.and_then(|lat| longitude.map(|lon| (lat, lon)));
    let stn = StationInfo::new_with_values(None, lat_lon, elevation);

    let year = msg.long("year").ok().and_then(|v| v.into_option());
    let month = msg.long("month").ok().and_then(|v| v.into_option());
    let day = msg.long("day").ok().and_then(|v| v.into_option());
    let hour = msg.long("hour").ok().and_then(|v| v.into_option());

    let vt = year
        .and_then(|y| month.map(|m| (y as i32, m as u32)))
        .and_then(|(y, m)| day.map(|d| (y, m, d as u32)))
        .and_then(|(y, m, d)| hour.map(|h| (y, m, d, h as u32)))
        .map(|(y, m, d, h)| NaiveDate::from_ymd(y, m, d).and_hms(h, 0, 0));

    let snd = Sounding::new()
        .with_station_info(stn)
        .with_valid_time(vt)
        .with_lead_time(0) // Lead time in hours for forecast soundings.
        .with_pressure_profile(p)
        .with_height_profile(h)
        .with_temperature_profile(t)
        .with_dew_point_profile(dp)
        .with_wind_profile(w);

    Ok(Analysis::new(snd))
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw [HTSlib](https://github.com/samtools/htslib) bindings.
//! Instead of using this crate directly, it is recommended to use [rust-htslib](https://docs.rs/rust-htslib) instead,
//! which has a more idiomatic and high-level API and builds on top of this crate.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// include on-the-fly generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<commit_msg>fix: dummy release<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw [HTSlib](https://github.com/samtools/htslib) bindings for reading and writing
//! genomics file formats like SAM, BAM, CRAM, VCF, BCF.
//! Instead of using this crate directly, it is recommended to use [rust-htslib](https://docs.rs/rust-htslib)
//! instead, which has a more idiomatic and high-level API and builds on top of this crate.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// include on-the-fly generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<|endoftext|>


<commit_before>use llvm_sys::execution_engine::*;
use super::*;
use std::mem;

pub struct ExecutionEngine {
    pub ptr: LLVMExecutionEngineRef,
}

impl ExecutionEngine {
    pub fn create_for_module(module: Module) -> Result<ExecutionEngine, &'static str> {
        unsafe {
            let mut ee = mem::uninitialized();
            let mut out = mem::zeroed();

            let res = LLVMCreateExecutionEngineForModule(&mut ee, module.ptr, &mut out);

            if res == 0 { // no error message was set
                Ok(ExecutionEngine{
                    ptr: ee
                })
            } else {
                Err(c_str_to_str!(out as *const i8))
            }
        }
    }
impl Drop for ExecutionEngine {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeExecutionEngine(self.ptr);
        }
    }
}
<commit_msg>Add get_functio_addr to ExecEngine<commit_after>use llvm_sys::execution_engine::*;
use super::*;
use std::mem;

pub struct ExecutionEngine {
    pub ptr: LLVMExecutionEngineRef,
}

impl ExecutionEngine {
    pub fn create_for_module(module: Module) -> Result<ExecutionEngine, &'static str> {
        unsafe {
            let mut ee = mem::uninitialized();
            let mut out = mem::zeroed();

            let res = LLVMCreateExecutionEngineForModule(&mut ee, module.ptr, &mut out);

            if res == 0 { // no error message was set
                Ok(ExecutionEngine{
                    ptr: ee
                })
            } else {
                Err(c_str_to_str!(out as *const i8))
            }
        }
    }

    pub fn get_function_address(&self, fname: &str) -> Option<extern "C" fn()> {
        let fname_s = CString::new(fname).unwrap();
        unsafe {
            let addr = LLVMGetFunctionAddress(self.ptr, fname_s.as_ptr());

            if addr == 0 {
                None
            } else {
                Some(mem::transmute(addr))
            }
        }
    }
}

impl Drop for ExecutionEngine {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposeExecutionEngine(self.ptr);
        }
    }
}

<|endoftext|>


<commit_before>mod iter;
mod coord;
mod test;

use traits::Grid;
use traits::Cell;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

pub struct SquareGrid<C, N>
    where C: Cell,
          N: Nhood<Coord=GridCoord> {

    cells: Vec<C>,
    old_cells: Vec<C>,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32
}

impl<C, N> SquareGrid<C, N>
    where C: Cell,
          N: Nhood<Coord=GridCoord> {

    pub fn new(rows: i32, cols: i32, nhood: N) -> Self {

        let len = (rows * cols) as usize;

        let cells = vec![C::default(); len];
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let mut grid = SquareGrid {
            cells: cells,
            old_cells: old_cells,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows)
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0 .. self.cells.len() {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols &&
               coord.y() >= 0 && coord.y() < self.rows {

                neighbors.push(Some(self.offset(coord)));
            }
            else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    fn neighbors_iter<'b>(&self,
                          cells: &'b Vec<C>,
                          neighbors: &'b Vec<Option<usize>>) -> Iter<'b, C> {

        Iter::new(cells, neighbors, self.nhood.neighbors_count())
    }

    #[inline]
    pub fn offset(&self, coord: &GridCoord) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for SquareGrid<C, N>
    where C: Cell,
          N: Nhood<Coord=GridCoord> {

    type Cell = C;
    type Coord = GridCoord;

    fn step(&mut self) {
        self.old_cells = self.cells.clone();

        for (cell_no, cell) in self.old_cells.iter().enumerate() {

            let ref neighbors = self.neighbors[cell_no];
            let neighbors_iter = self.neighbors_iter(&self.old_cells, &neighbors);

            let new_cell = cell.step(neighbors_iter);

            self.cells[cell_no] = new_cell;
        }
    }

    fn restore<G: Grid>(&mut self, other: &G) {

        debug_assert_eq!(self.dimensions().x(), other.dimensions().x());
        debug_assert_eq!(self.dimensions().y(), other.dimensions().y());

    }

    fn cells(&self) -> &Vec<C> {
        &self.cells
    }

    fn dimensions(&self) -> Self::Coord {
        self.dimensions.clone()
    }
}
<commit_msg>Impl new trait methods.<commit_after>mod iter;
mod coord;
mod test;

use traits::Grid;
use traits::Cell;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

pub struct SquareGrid<C, N>
    where C: Cell,
          N: Nhood<Coord=GridCoord> {

    cells: Vec<C>,
    old_cells: Vec<C>,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32
}

impl<C, N> SquareGrid<C, N>
    where C: Cell,
          N: Nhood<Coord=GridCoord> {

    pub fn new(rows: i32, cols: i32, nhood: N) -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let mut grid = SquareGrid {
            cells: cells,
            old_cells: old_cells,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows)
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0 .. self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            self.cells.push(C::with_coord(coord));

        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols &&
               coord.y() >= 0 && coord.y() < self.rows {

                neighbors.push(Some(self.offset(coord)));
            }
            else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    fn neighbors_iter<'b>(&self,
                          cells: &'b Vec<C>,
                          neighbors: &'b Vec<Option<usize>>) -> Iter<'b, C> {

        Iter::new(cells, neighbors, self.nhood.neighbors_count())
    }

    #[inline]
    pub fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for SquareGrid<C, N>
    where C: Cell,
          N: Nhood<Coord=GridCoord> {

    type Cell = C;
    type Coord = GridCoord;

    fn step(&mut self) {
        self.old_cells = self.cells.clone();

        for (cell_no, cell) in self.old_cells.iter().enumerate() {

            let ref neighbors = self.neighbors[cell_no];
            let neighbors_iter = self.neighbors_iter(&self.old_cells, &neighbors);

            let new_cell = cell.step(neighbors_iter);

            self.cells[cell_no] = new_cell;
        }
    }

    fn restore<G: Grid>(&mut self, other: &G) {

        debug_assert_eq!(self.dimensions().x(), other.dimensions().x());
        debug_assert_eq!(self.dimensions().y(), other.dimensions().y());

        unimplemented!();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> {
        &self.cells
    }

    fn dimensions(&self) -> Self::Coord {
        self.dimensions.clone()
    }
}
<|endoftext|>


<commit_before>//! Utility module for helpers around drawing [`WlSurface`]s with [`Renderer`]s.

use crate::{
    backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture},
    utils::{Buffer, Logical, Point, Rectangle, Size, Transform},
    wayland::compositor::{
        is_sync_subsurface, with_surface_tree_upward, BufferAssignment, Damage, SubsurfaceCachedState,
        SurfaceAttributes, TraversalAction,
    },
};
#[cfg(feature = "desktop")]
use std::collections::HashSet;
use std::{
    any::TypeId,
    cell::RefCell,
    collections::{hash_map::Entry, HashMap},
};
use wayland_server::protocol::{wl_buffer::WlBuffer, wl_surface::WlSurface};

#[derive(Default)]
pub(crate) struct SurfaceState {
    pub(crate) buffer_dimensions: Option<Size<i32, Buffer>>,
    pub(crate) buffer_scale: i32,
    pub(crate) buffer_transform: Transform,
    pub(crate) buffer: Option<WlBuffer>,
    pub(crate) textures: HashMap<(TypeId, usize), Box<dyn std::any::Any>>,
    #[cfg(feature = "desktop")]
    pub(crate) damage_seen: HashSet<crate::desktop::space::SpaceOutputHash>,
}

impl SurfaceState {
    pub fn update_buffer(&mut self, attrs: &mut SurfaceAttributes) {
        match attrs.buffer.take() {
            Some(BufferAssignment::NewBuffer { buffer, .. }) => {
                // new contents
                self.buffer_dimensions = buffer_dimensions(&buffer);
                self.buffer_scale = attrs.buffer_scale;
                self.buffer_transform = attrs.buffer_transform.into();
                if let Some(old_buffer) = std::mem::replace(&mut self.buffer, Some(buffer)) {
                    if &old_buffer != self.buffer.as_ref().unwrap() {
                        old_buffer.release();
                    }
                }
                self.textures.clear();
                #[cfg(feature = "desktop")]
                self.damage_seen.clear();
            }
            Some(BufferAssignment::Removed) => {
                // remove the contents
                self.buffer_dimensions = None;
                if let Some(buffer) = self.buffer.take() {
                    buffer.release();
                };
                self.textures.clear();
                #[cfg(feature = "desktop")]
                self.damage_seen.clear();
            }
            None => {}
        }
    }

    /// Returns the size of the surface.
    pub fn surface_size(&self) -> Option<Size<i32, Logical>> {
        self.buffer_dimensions
            .as_ref()
            .map(|dim| dim.to_logical(self.buffer_scale, self.buffer_transform))
    }
}

/// Handler to let smithay take over buffer management.
///
/// Needs to be called first on the commit-callback of
/// [`crate::wayland::compositor::compositor_init`].
///
/// Consumes the buffer of [`SurfaceAttributes`], the buffer will
/// not be accessible anymore, but [`draw_surface_tree`] and other
/// `draw_*` helpers of the [desktop module](`crate::desktop`) will
/// become usable for surfaces handled this way.
pub fn on_commit_buffer_handler(surface: &WlSurface) {
    if !is_sync_subsurface(surface) {
        with_surface_tree_upward(
            surface,
            (),
            |_, _, _| TraversalAction::DoChildren(()),
            |_surf, states, _| {
                states
                    .data_map
                    .insert_if_missing(|| RefCell::new(SurfaceState::default()));
                let mut data = states
                    .data_map
                    .get::<RefCell<SurfaceState>>()
                    .unwrap()
                    .borrow_mut();
                data.update_buffer(&mut *states.cached_state.current::<SurfaceAttributes>());
            },
            |_, _, _| true,
        );
    }
}

/// Draws a surface and its subsurfaces using a given [`Renderer`] and [`Frame`].
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the surface should be drawn at.
/// - `damage` is the set of regions of the surface that should be drawn.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn draw_surface_tree<R, E, F, T>(
    renderer: &mut R,
    frame: &mut F,
    surface: &WlSurface,
    scale: f64,
    location: Point<i32, Logical>,
    damage: &[Rectangle<i32, Logical>],
    log: &slog::Logger,
) -> Result<(), R::Error>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    let mut result = Ok(());
    let texture_id = (TypeId::of::<T>(), renderer.id());
    with_surface_tree_upward(
        surface,
        location,
        |_surface, states, location| {
            let mut location = *location;
            if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                let mut data_ref = data.borrow_mut();
                let data = &mut *data_ref;
                let attributes = states.cached_state.current::<SurfaceAttributes>();
                // Import a new buffer if necessary
                let surface_size = data.surface_size().unwrap();
                if let Entry::Vacant(e) = data.textures.entry(texture_id) {
                    if let Some(buffer) = data.buffer.as_ref() {
                        let buffer_damage = attributes
                            .damage
                            .iter()
                            .map(|dmg| match dmg {
                                Damage::Buffer(rect) => *rect,
                                Damage::Surface(rect) => rect.to_buffer(
                                    attributes.buffer_scale,
                                    attributes.buffer_transform.into(),
                                    &surface_size,
                                ),
                            })
                            .collect::<Vec<_>>();

                        match renderer.import_buffer(buffer, Some(states), &buffer_damage) {
                            Some(Ok(m)) => {
                                e.insert(Box::new(m));
                            }
                            Some(Err(err)) => {
                                slog::warn!(log, "Error loading buffer: {}", err);
                            }
                            None => {
                                slog::error!(log, "Unknown buffer format for: {:?}", buffer);
                            }
                        }
                    }
                }
                // Now, should we be drawn ?
                if data.textures.contains_key(&texture_id) {
                    // if yes, also process the children
                    if states.role == Some("subsurface") {
                        let current = states.cached_state.current::<SubsurfaceCachedState>();
                        location += current.location;
                    }
                    TraversalAction::DoChildren(location)
                } else {
                    // we are not displayed, so our children are neither
                    TraversalAction::SkipChildren
                }
            } else {
                // we are not displayed, so our children are neither
                TraversalAction::SkipChildren
            }
        },
        |_surface, states, location| {
            let mut location = *location;
            if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                let mut data = data.borrow_mut();
                let dimensions = data.surface_size();
                let buffer_scale = data.buffer_scale;
                let buffer_transform = data.buffer_transform;
                let attributes = states.cached_state.current::<SurfaceAttributes>();
                if let Some(texture) = data
                    .textures
                    .get_mut(&texture_id)
                    .and_then(|x| x.downcast_mut::<T>())
                {
                    let dimensions = dimensions.unwrap();
                    // we need to re-extract the subsurface offset, as the previous closure
                    // only passes it to our children
                    let mut surface_offset = (0, 0).into();
                    if states.role == Some("subsurface") {
                        let current = states.cached_state.current::<SubsurfaceCachedState>();
                        surface_offset = current.location;
                        location += current.location;
                    }

                    let damage = damage
                        .iter()
                        .cloned()
                        // first move the damage by the surface offset in logical space
                        .map(|mut geo| {
                            // make the damage relative to the surfaec
                            geo.loc -= surface_offset;
                            geo
                        })
                        // then clamp to surface size again in logical space
                        .flat_map(|geo| geo.intersection(Rectangle::from_loc_and_size((0, 0), dimensions)))
                        // lastly transform it into buffer space
                        .map(|geo| geo.to_buffer(buffer_scale, buffer_transform, &dimensions))
                        .collect::<Vec<_>>();

                    // TODO: Take wp_viewporter into account
                    if let Err(err) = frame.render_texture_at(
                        texture,
                        location.to_f64().to_physical(scale).to_i32_round(),
                        buffer_scale,
                        scale,
                        attributes.buffer_transform.into(),
                        &damage,
                        1.0,
                    ) {
                        result = Err(err);
                    }
                }
            }
        },
        |_, _, _| true,
    );

    result
}
<commit_msg>renderer: Add utils::import_surface_tree<commit_after>//! Utility module for helpers around drawing [`WlSurface`]s with [`Renderer`]s.

use crate::{
    backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture},
    utils::{Buffer, Logical, Point, Rectangle, Size, Transform},
    wayland::compositor::{
        is_sync_subsurface, with_surface_tree_upward, BufferAssignment, Damage, SubsurfaceCachedState,
        SurfaceAttributes, TraversalAction,
    },
};
#[cfg(feature = "desktop")]
use std::collections::HashSet;
use std::{
    any::TypeId,
    cell::RefCell,
    collections::{hash_map::Entry, HashMap},
};
use wayland_server::protocol::{wl_buffer::WlBuffer, wl_surface::WlSurface};

#[derive(Default)]
pub(crate) struct SurfaceState {
    pub(crate) buffer_dimensions: Option<Size<i32, Buffer>>,
    pub(crate) buffer_scale: i32,
    pub(crate) buffer_transform: Transform,
    pub(crate) buffer: Option<WlBuffer>,
    pub(crate) textures: HashMap<(TypeId, usize), Box<dyn std::any::Any>>,
    #[cfg(feature = "desktop")]
    pub(crate) damage_seen: HashSet<crate::desktop::space::SpaceOutputHash>,
}

impl SurfaceState {
    pub fn update_buffer(&mut self, attrs: &mut SurfaceAttributes) {
        match attrs.buffer.take() {
            Some(BufferAssignment::NewBuffer { buffer, .. }) => {
                // new contents
                self.buffer_dimensions = buffer_dimensions(&buffer);
                self.buffer_scale = attrs.buffer_scale;
                self.buffer_transform = attrs.buffer_transform.into();
                if let Some(old_buffer) = std::mem::replace(&mut self.buffer, Some(buffer)) {
                    if &old_buffer != self.buffer.as_ref().unwrap() {
                        old_buffer.release();
                    }
                }
                self.textures.clear();
                #[cfg(feature = "desktop")]
                self.damage_seen.clear();
            }
            Some(BufferAssignment::Removed) => {
                // remove the contents
                self.buffer_dimensions = None;
                if let Some(buffer) = self.buffer.take() {
                    buffer.release();
                };
                self.textures.clear();
                #[cfg(feature = "desktop")]
                self.damage_seen.clear();
            }
            None => {}
        }
    }

    /// Returns the size of the surface.
    pub fn surface_size(&self) -> Option<Size<i32, Logical>> {
        self.buffer_dimensions
            .as_ref()
            .map(|dim| dim.to_logical(self.buffer_scale, self.buffer_transform))
    }
}

/// Handler to let smithay take over buffer management.
///
/// Needs to be called first on the commit-callback of
/// [`crate::wayland::compositor::compositor_init`].
///
/// Consumes the buffer of [`SurfaceAttributes`], the buffer will
/// not be accessible anymore, but [`draw_surface_tree`] and other
/// `draw_*` helpers of the [desktop module](`crate::desktop`) will
/// become usable for surfaces handled this way.
pub fn on_commit_buffer_handler(surface: &WlSurface) {
    if !is_sync_subsurface(surface) {
        with_surface_tree_upward(
            surface,
            (),
            |_, _, _| TraversalAction::DoChildren(()),
            |_surf, states, _| {
                states
                    .data_map
                    .insert_if_missing(|| RefCell::new(SurfaceState::default()));
                let mut data = states
                    .data_map
                    .get::<RefCell<SurfaceState>>()
                    .unwrap()
                    .borrow_mut();
                data.update_buffer(&mut *states.cached_state.current::<SurfaceAttributes>());
            },
            |_, _, _| true,
        );
    }
}

/// Imports buffers of a surface and its subsurfaces using a given [`Renderer`].
///
/// This can be called early as an optimization, if `draw_surface_tree` is used later.
/// `draw_surface_tree` will also import buffers as necessary, but calling `import_surface_tree`
/// already may allow buffer imports to happen before compositing takes place, depending
/// on your event loop.
///
/// Note: This will do nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn import_surface_tree<R>(
    renderer: &mut R,
    surface: &WlSurface,
    log: &slog::Logger,
) -> Result<(), <R as Renderer>::Error>
where
    R: Renderer + ImportAll,
    <R as Renderer>::TextureId: 'static,
{
    let mut result = Ok(());
    let texture_id = (TypeId::of::<<R as Renderer>::TextureId>(), renderer.id());
    with_surface_tree_upward(
        surface,
        (),
        |_surface, states, _| {
            if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                let mut data_ref = data.borrow_mut();
                let data = &mut *data_ref;
                let attributes = states.cached_state.current::<SurfaceAttributes>();
                // Import a new buffer if available
                let surface_size = data.surface_size().unwrap();
                if let Entry::Vacant(e) = data.textures.entry(texture_id) {
                    if let Some(buffer) = data.buffer.as_ref() {
                        let buffer_damage = attributes
                            .damage
                            .iter()
                            .map(|dmg| match dmg {
                                Damage::Buffer(rect) => *rect,
                                Damage::Surface(rect) => rect.to_buffer(
                                    attributes.buffer_scale,
                                    attributes.buffer_transform.into(),
                                    &surface_size,
                                ),
                            })
                            .collect::<Vec<_>>();

                        match renderer.import_buffer(buffer, Some(states), &buffer_damage) {
                            Some(Ok(m)) => {
                                e.insert(Box::new(m));
                            }
                            Some(Err(err)) => {
                                slog::warn!(log, "Error loading buffer: {}", err);
                                result = Err(err);
                            }
                            None => {
                                slog::error!(log, "Unknown buffer format for: {:?}", buffer);
                            }
                        }
                    }
                }
                // Now, was the import successful?
                if data.textures.contains_key(&texture_id) {
                    TraversalAction::DoChildren(())
                } else {
                    // we are not displayed, so our children are neither
                    TraversalAction::SkipChildren
                }
            } else {
                // we are not displayed, so our children are neither
                TraversalAction::SkipChildren
            }
        },
        |_, _, _| {},
        |_, _, _| true,
    );

    result
}

/// Draws a surface and its subsurfaces using a given [`Renderer`] and [`Frame`].
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the surface should be drawn at.
/// - `damage` is the set of regions of the surface that should be drawn.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn draw_surface_tree<R, E, F, T>(
    renderer: &mut R,
    frame: &mut F,
    surface: &WlSurface,
    scale: f64,
    location: Point<i32, Logical>,
    damage: &[Rectangle<i32, Logical>],
    log: &slog::Logger,
) -> Result<(), R::Error>
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    let mut result = Ok(());
    let texture_id = (TypeId::of::<T>(), renderer.id());
    with_surface_tree_upward(
        surface,
        location,
        |_surface, states, location| {
            let mut location = *location;
            if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                let mut data_ref = data.borrow_mut();
                let data = &mut *data_ref;
                let attributes = states.cached_state.current::<SurfaceAttributes>();
                // Import a new buffer if necessary
                let surface_size = data.surface_size().unwrap();
                if let Entry::Vacant(e) = data.textures.entry(texture_id) {
                    if let Some(buffer) = data.buffer.as_ref() {
                        let buffer_damage = attributes
                            .damage
                            .iter()
                            .map(|dmg| match dmg {
                                Damage::Buffer(rect) => *rect,
                                Damage::Surface(rect) => rect.to_buffer(
                                    attributes.buffer_scale,
                                    attributes.buffer_transform.into(),
                                    &surface_size,
                                ),
                            })
                            .collect::<Vec<_>>();

                        match renderer.import_buffer(buffer, Some(states), &buffer_damage) {
                            Some(Ok(m)) => {
                                e.insert(Box::new(m));
                            }
                            Some(Err(err)) => {
                                slog::warn!(log, "Error loading buffer: {}", err);
                            }
                            None => {
                                slog::error!(log, "Unknown buffer format for: {:?}", buffer);
                            }
                        }
                    }
                }
                // Now, should we be drawn ?
                if data.textures.contains_key(&texture_id) {
                    // if yes, also process the children
                    if states.role == Some("subsurface") {
                        let current = states.cached_state.current::<SubsurfaceCachedState>();
                        location += current.location;
                    }
                    TraversalAction::DoChildren(location)
                } else {
                    // we are not displayed, so our children are neither
                    TraversalAction::SkipChildren
                }
            } else {
                // we are not displayed, so our children are neither
                TraversalAction::SkipChildren
            }
        },
        |_surface, states, location| {
            let mut location = *location;
            if let Some(data) = states.data_map.get::<RefCell<SurfaceState>>() {
                let mut data = data.borrow_mut();
                let dimensions = data.surface_size();
                let buffer_scale = data.buffer_scale;
                let buffer_transform = data.buffer_transform;
                let attributes = states.cached_state.current::<SurfaceAttributes>();
                if let Some(texture) = data
                    .textures
                    .get_mut(&texture_id)
                    .and_then(|x| x.downcast_mut::<T>())
                {
                    let dimensions = dimensions.unwrap();
                    // we need to re-extract the subsurface offset, as the previous closure
                    // only passes it to our children
                    let mut surface_offset = (0, 0).into();
                    if states.role == Some("subsurface") {
                        let current = states.cached_state.current::<SubsurfaceCachedState>();
                        surface_offset = current.location;
                        location += current.location;
                    }

                    let damage = damage
                        .iter()
                        .cloned()
                        // first move the damage by the surface offset in logical space
                        .map(|mut geo| {
                            // make the damage relative to the surfaec
                            geo.loc -= surface_offset;
                            geo
                        })
                        // then clamp to surface size again in logical space
                        .flat_map(|geo| geo.intersection(Rectangle::from_loc_and_size((0, 0), dimensions)))
                        // lastly transform it into buffer space
                        .map(|geo| geo.to_buffer(buffer_scale, buffer_transform, &dimensions))
                        .collect::<Vec<_>>();

                    // TODO: Take wp_viewporter into account
                    if let Err(err) = frame.render_texture_at(
                        texture,
                        location.to_f64().to_physical(scale).to_i32_round(),
                        buffer_scale,
                        scale,
                        attributes.buffer_transform.into(),
                        &damage,
                        1.0,
                    ) {
                        result = Err(err);
                    }
                }
            }
        },
        |_, _, _| true,
    );

    result
}
<|endoftext|>


<commit_before>use {Event, Input};

/// Close arguments.
#[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct CloseArgs;

/// Window is closing.
pub trait CloseEvent: Sized {
    /// Creates a close event from arguments.
    fn from_close_args(args: &CloseArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a close event.
    fn close<U, F>(&self, f: F) -> Option<U> where F: FnMut(&CloseArgs) -> U;
    /// Returns close arguments.
    fn close_args(&self) -> Option<CloseArgs> {
        self.close(|args| args.clone())
    }
}

impl CloseEvent for Event {
    fn from_close_args(args: &CloseArgs, _old_event: &Self) -> Option<Self> {
        Some(Event::Input(Input::Close(*args)))
    }

    fn close<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(&CloseArgs) -> U
    {
        match *self {
            Event::Input(Input::Close(ref args)) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_close() {
        use CloseArgs;
        use Event;

        let e: Event = CloseArgs.into();
        let x: Option<Event> = CloseEvent::from_close_args(&CloseArgs, &e);
        let y: Option<Event> = x.clone()
            .unwrap()
            .close(|args| CloseEvent::from_close_args(args, x.as_ref().unwrap()))
            .unwrap();
        assert_eq!(x, y);
    }
}
<commit_msg>Added more derive traits for `CloseArgs`<commit_after>use {Event, Input};

/// Close arguments.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize, Hash)]
pub struct CloseArgs;

/// Window is closing.
pub trait CloseEvent: Sized {
    /// Creates a close event from arguments.
    fn from_close_args(args: &CloseArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a close event.
    fn close<U, F>(&self, f: F) -> Option<U> where F: FnMut(&CloseArgs) -> U;
    /// Returns close arguments.
    fn close_args(&self) -> Option<CloseArgs> {
        self.close(|args| args.clone())
    }
}

impl CloseEvent for Event {
    fn from_close_args(args: &CloseArgs, _old_event: &Self) -> Option<Self> {
        Some(Event::Input(Input::Close(*args)))
    }

    fn close<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(&CloseArgs) -> U
    {
        match *self {
            Event::Input(Input::Close(ref args)) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_close() {
        use CloseArgs;
        use Event;

        let e: Event = CloseArgs.into();
        let x: Option<Event> = CloseEvent::from_close_args(&CloseArgs, &e);
        let y: Option<Event> = x.clone()
            .unwrap()
            .close(|args| CloseEvent::from_close_args(args, x.as_ref().unwrap()))
            .unwrap();
        assert_eq!(x, y);
    }
}
<|endoftext|>