<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};
use std::ptr;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::swiper::{CARD_SIZE, PROMOTION_AGE, Region};
use gc::swiper::card::CardTable;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use object::Obj;
use timer::{in_ms, Timer};

pub struct YoungGen {
    // bounds of from- & to-space
    total: Region,

    // address that separates from & to-space
    separator: Address,

    // address of next free memory
    free: AtomicUsize,

    // end of free memory (either separator or total.end)
    end: AtomicUsize,
}

impl YoungGen {
    pub fn new(young_start: Address, young_end: Address) -> YoungGen {
        let half_size = (young_end.to_usize() - young_start.to_usize()) / 2;
        let half_address = young_start.offset(half_size);

        YoungGen {
            total: Region::new(young_start, young_end),
            separator: half_address,
            free: AtomicUsize::new(young_start.to_usize()),
            end: AtomicUsize::new(half_address.to_usize()),
        }
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        let mut old = self.free.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new >= self.end.load(Ordering::Relaxed) {
                return ptr::null();
            }

            let res = self.free.compare_exchange_weak(
                old,
                new,
                Ordering::SeqCst,
                Ordering::Relaxed,
            );

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old as *const u8
    }

    pub fn collect(
        &self,
        ctxt: &SemContext,
        rootset: Vec<IndirectObj>,
        card_table: &CardTable,
        crossing_map: &CrossingMap,
        old: &OldGen,
    ) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        let mut scan;
        let scan_end: Address = self.free.load(Ordering::SeqCst).into();

        let mut free;
        let new_end;

        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            scan = self.total.start;
            free = self.separator;
            new_end = self.total.end;

        } else {
            scan = self.separator;
            free = self.total.start;
            new_end = self.separator;
        }

        // copy all references from roots into young generation
        for &root in &rootset {
            let root_ptr = root.get();

            if self.total.includes(Address::from_ptr(root_ptr)) {
                root.set(copy(root_ptr, &mut free, old));
            }
        }

        // copy all references from dirty cards into young generation
        copy_dirty_cards(card_table, crossing_map, &mut free, &self.total, old);

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

            object.visit_reference_fields(|child| {
                let child_ptr = child.get();

                if self.total.includes(Address::from_ptr(child_ptr)) {
                    child.set(copy(child_ptr, &mut free, old));
                }
            });

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

        // swap spaces
        self.end.store(new_end.to_usize(), Ordering::Relaxed);

        // update start of free memory
        self.free.store(free.to_usize(), Ordering::SeqCst);

        // memset from-space to garbage data for debug builds
        // makes sure that no pointer into from-space is left
        if cfg!(debug_assertions) {
            let start = if new_end == self.separator {
                self.total.start
            } else {
                self.separator
            };

            let size = self.separator.to_usize() - self.total.start.to_usize();

            unsafe {
                ptr::write_bytes(start.to_mut_ptr::<u8>(), 0xcc, size);
            }
        }

        timer.stop_with(|dur| if ctxt.args.flag_gc_events {
            println!("GC minor: collect garbage ({} ms)", in_ms(dur));
        });
    }
}

fn copy_dirty_cards(
    card_table: &CardTable,
    crossing_map: &CrossingMap,
    mut free: &mut Address,
    young: &Region,
    old: &OldGen,
) {
    // copy objects for old -> young references
    card_table.visit_dirty(|card| {
        let crossing_entry = crossing_map.get(card);

        // card contains: any data but no references, then first object
        if crossing_entry.is_first_object() {
            let card_address = crossing_map.address_of_card(card);

            // first_object() returns number of words before end of card
            let offset_from_end = crossing_entry.first_object() as usize * 8;
            let ptr = card_address.offset(CARD_SIZE - offset_from_end);

            let end = card_address.offset(CARD_SIZE);

            // copy all objects from this card
            copy_card(ptr, end, free, young, old);

        // card contains: references, then first object
        } else if crossing_entry.is_references_at_start() {
            let number_references = crossing_entry.references_at_start() as usize;
            let card_address = crossing_map.address_of_card(card);
            let mut ptr = card_address;

            for _ in 0..number_references {
                let ind_ptr = IndirectObj::from_address(ptr);
                let dir_ptr = ind_ptr.get();

                if young.includes(Address::from_ptr(dir_ptr)) {
                    ind_ptr.set(copy(dir_ptr, &mut free, old));
                }

                ptr = ptr.offset(8);
            }

            let end = card_address.offset(CARD_SIZE);

            // copy all objects from this card
            copy_card(ptr, end, free, young, old);

        // object spans multiple cards
        } else if crossing_entry.is_previous_card() {
            unimplemented!();

        } else {
            assert!(crossing_entry.is_no_references());
            panic!("dirty card without references: can this ever happen?");
        }
    });
}

fn copy_card(mut ptr: Address, end: Address, mut free: &mut Address, young: &Region, old: &OldGen) {
    while ptr < end {
        let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if young.includes(Address::from_ptr(child_ptr)) {
                child.set(copy(child_ptr, &mut free, old));
            }
        });

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

pub fn copy(obj: *mut Obj, free: &mut Address, old: &OldGen) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let addr = get_forwarding_address(obj);

    if is_forwarding_address(addr) {
        unmark_forwarding_address(addr).to_mut_ptr::<Obj>()
    } else {
        let obj_size = obj.size();
        let age = obj.header_mut().increase_age();

        let addr: Address;

        // if object is old enough we copy it into the old generation
        if age >= PROMOTION_AGE {
            addr = Address::from_ptr(old.alloc(obj_size));
            copy_object(obj, addr, obj_size);

        // otherwise the object remains in the young generation for now
        } else {
            addr = *free;
            copy_object(obj, addr, obj_size);
            *free = addr.offset(obj_size);
        }

        set_forwarding_address(obj, addr);

        addr.to_mut_ptr::<Obj>()
    }
}

fn copy_object(obj: &Obj, addr: Address, size: usize) {
    unsafe {
        ptr::copy_nonoverlapping(
            obj as *const Obj as *const u8,
            addr.to_mut_ptr::<u8>(),
            size,
        );
    }
}

pub fn is_forwarding_address(obj: Address) -> bool {
    (obj.to_usize() & 1) == 1
}

pub fn mark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() | 1).into()
}

pub fn unmark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() & !1).into()
}

pub fn get_forwarding_address(obj: &Obj) -> Address {
    unsafe { *(obj as *const Obj as *const Address) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: Address) {
    unsafe {
        *(obj as *mut Obj as *mut Address) = mark_forwarding_address(addr);
    }
}
<commit_msg>started handling previous_card-entry in crossings<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use std::ptr;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::swiper::{CARD_SIZE, PROMOTION_AGE, Region};
use gc::swiper::card::CardTable;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use mem;
use object::Obj;
use timer::{in_ms, Timer};

pub struct YoungGen {
    // bounds of from- & to-space
    total: Region,

    // address that separates from & to-space
    separator: Address,

    // address of next free memory
    free: AtomicUsize,

    // end of free memory (either separator or total.end)
    end: AtomicUsize,
}

impl YoungGen {
    pub fn new(young_start: Address, young_end: Address) -> YoungGen {
        let half_size = (young_end.to_usize() - young_start.to_usize()) / 2;
        let half_address = young_start.offset(half_size);

        YoungGen {
            total: Region::new(young_start, young_end),
            separator: half_address,
            free: AtomicUsize::new(young_start.to_usize()),
            end: AtomicUsize::new(half_address.to_usize()),
        }
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        let mut old = self.free.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new >= self.end.load(Ordering::Relaxed) {
                return ptr::null();
            }

            let res = self.free.compare_exchange_weak(
                old,
                new,
                Ordering::SeqCst,
                Ordering::Relaxed,
            );

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old as *const u8
    }

    pub fn collect(
        &self,
        ctxt: &SemContext,
        rootset: Vec<IndirectObj>,
        card_table: &CardTable,
        crossing_map: &CrossingMap,
        old: &OldGen,
    ) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        let mut scan;
        let scan_end: Address = self.free.load(Ordering::SeqCst).into();

        let mut free;
        let new_end;

        if self.end.load(Ordering::Relaxed) == self.separator.to_usize() {
            scan = self.total.start;
            free = self.separator;
            new_end = self.total.end;

        } else {
            scan = self.separator;
            free = self.total.start;
            new_end = self.separator;
        }

        // copy all references from roots into young generation
        for &root in &rootset {
            let root_ptr = root.get();

            if self.total.includes(Address::from_ptr(root_ptr)) {
                root.set(copy(root_ptr, &mut free, old));
            }
        }

        // copy all references from dirty cards into young generation
        copy_dirty_cards(card_table, crossing_map, &mut free, &self.total, old);

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

            object.visit_reference_fields(|child| {
                let child_ptr = child.get();

                if self.total.includes(Address::from_ptr(child_ptr)) {
                    child.set(copy(child_ptr, &mut free, old));
                }
            });

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

        // swap spaces
        self.end.store(new_end.to_usize(), Ordering::Relaxed);

        // update start of free memory
        self.free.store(free.to_usize(), Ordering::SeqCst);

        // memset from-space to garbage data for debug builds
        // makes sure that no pointer into from-space is left
        if cfg!(debug_assertions) {
            let start = if new_end == self.separator {
                self.total.start
            } else {
                self.separator
            };

            let size = self.separator.to_usize() - self.total.start.to_usize();

            unsafe {
                ptr::write_bytes(start.to_mut_ptr::<u8>(), 0xcc, size);
            }
        }

        timer.stop_with(|dur| if ctxt.args.flag_gc_events {
            println!("GC minor: collect garbage ({} ms)", in_ms(dur));
        });
    }
}

// copy all references from old- into young-generation.
fn copy_dirty_cards(
    card_table: &CardTable,
    crossing_map: &CrossingMap,
    mut free: &mut Address,
    young: &Region,
    old: &OldGen,
) {
    card_table.visit_dirty(|card| {
        let crossing_entry = crossing_map.get(card);

        // card contains: any data but no references, then first object
        if crossing_entry.is_first_object() {
            let card_address = crossing_map.address_of_card(card);

            // first_object() returns number of words before end of card
            let offset_from_end = crossing_entry.first_object() as usize * ptr_width();
            let ptr = card_address.offset(CARD_SIZE - offset_from_end);

            let end = card_address.offset(CARD_SIZE);

            // copy all objects from this card
            copy_card(ptr, end, free, young, old);

        // card contains: references, then first object
        } else if crossing_entry.is_references_at_start() {
            let number_references = crossing_entry.references_at_start() as usize;
            let card_address = crossing_map.address_of_card(card);
            let mut ptr = card_address;

            for _ in 0..number_references {
                let ind_ptr = IndirectObj::from_address(ptr);
                let dir_ptr = ind_ptr.get();

                if young.includes(Address::from_ptr(dir_ptr)) {
                    ind_ptr.set(copy(dir_ptr, &mut free, old));
                }

                ptr = ptr.offset(ptr_width());
            }

            let end = card_address.offset(CARD_SIZE);

            // copy all objects from this card
            copy_card(ptr, end, free, young, old);

        // object spans multiple cards
        } else if crossing_entry.is_previous_card() {
            let mut previous = card - crossing_entry.previous_card() as usize;
            let mut crossing_entry = crossing_map.get(previous);

            while crossing_entry.is_previous_card() {
                previous = previous - crossing_entry.previous_card() as usize;
                crossing_entry = crossing_map.get(previous);
            }

            let previous_address = crossing_map.address_of_card(previous);
            let mut ptr;

            if crossing_entry.is_references_at_start() {
                let number_references = crossing_entry.references_at_start() as usize;
                ptr = previous_address.offset(number_references * ptr_width());

            } else if crossing_entry.is_first_object() {
                let offset_from_end = crossing_entry.first_object() as usize * ptr_width();
                ptr = previous_address.offset(CARD_SIZE - offset_from_end);

            } else {
                assert!(crossing_entry.is_no_references());
                panic!("dirty card without references: is this allowed to happen?");
            }

            let card_address = crossing_map.address_of_card(card);
            let mut last_object = ptr;

            while ptr < card_address {
                let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

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

            // last_object now stores pointer that reaches into current card
            // TODO: handle fields in last_object

            copy_card(ptr, card_address.offset(CARD_SIZE), free, young, old);

        } else {
            assert!(crossing_entry.is_no_references());
            panic!("dirty card without references: is this allowed to happen?");
        }
    });
}

fn copy_card(mut ptr: Address, end: Address, mut free: &mut Address, young: &Region, old: &OldGen) {
    while ptr < end {
        let object = unsafe { &mut *ptr.to_mut_ptr::<Obj>() };

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if young.includes(Address::from_ptr(child_ptr)) {
                child.set(copy(child_ptr, &mut free, old));
            }
        });

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

pub fn copy(obj: *mut Obj, free: &mut Address, old: &OldGen) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let addr = get_forwarding_address(obj);

    if is_forwarding_address(addr) {
        unmark_forwarding_address(addr).to_mut_ptr::<Obj>()
    } else {
        let obj_size = obj.size();
        let age = obj.header_mut().increase_age();

        let addr: Address;

        // if object is old enough we copy it into the old generation
        if age >= PROMOTION_AGE {
            addr = Address::from_ptr(old.alloc(obj_size));
            copy_object(obj, addr, obj_size);

        // otherwise the object remains in the young generation for now
        } else {
            addr = *free;
            copy_object(obj, addr, obj_size);
            *free = addr.offset(obj_size);
        }

        set_forwarding_address(obj, addr);

        addr.to_mut_ptr::<Obj>()
    }
}

fn copy_object(obj: &Obj, addr: Address, size: usize) {
    unsafe {
        ptr::copy_nonoverlapping(
            obj as *const Obj as *const u8,
            addr.to_mut_ptr::<u8>(),
            size,
        );
    }
}

pub fn is_forwarding_address(obj: Address) -> bool {
    (obj.to_usize() & 1) == 1
}

pub fn mark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() | 1).into()
}

pub fn unmark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() & !1).into()
}

pub fn get_forwarding_address(obj: &Obj) -> Address {
    unsafe { *(obj as *const Obj as *const Address) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: Address) {
    unsafe {
        *(obj as *mut Obj as *mut Address) = mark_forwarding_address(addr);
    }
}

#[inline(always)]
fn ptr_width() -> usize {
    mem::ptr_width() as usize
}<|endoftext|>


<commit_before>use super::Span;
use super::dimensions::{self, Dimension, Partitioned};
use rand::ThreadRng;
use std::fmt::Debug;
use std::ops::Add;
use std::iter::FromIterator;
use std::slice::Iter as SliceIter;
use std::collections::HashMap;
use std::collections::hash_map::Iter as HashMapIter;

/// Trait for defining geometric spaces.
pub trait Space {
    /// The data representation of the space.
    type Repr: Debug + Clone;

    /// Generate a random sample from the space.
    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr;

    /// Return the number of dimensions in the space.
    fn dim(&self) -> usize;

    /// Return the number of linear combinations of values in the space.
    fn span(&self) -> Span;
}

/// Geometric space for agent actions.
///
/// Currently the only supported representation for actions. In future we will need to handle
/// continuous actions.
pub type ActionSpace = UnitarySpace<dimensions::Discrete>;

/// An empty space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct EmptySpace;

impl Space for EmptySpace {
    type Repr = ();

    fn sample(&self, _: &mut ThreadRng) -> Self::Repr {
        ()
    }

    fn dim(&self) -> usize {
        0
    }

    fn span(&self) -> Span {
        Span::Null
    }
}

/// 1-dimensional space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct UnitarySpace<D: Dimension>(D);

impl<D: Dimension> UnitarySpace<D> {
    pub fn new(d: D) -> Self {
        UnitarySpace(d)
    }
}

impl UnitarySpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> UnitarySpace<Partitioned> {
        UnitarySpace(Partitioned::from_continuous(self.0, density))
    }
}

impl<D: Dimension> Space for UnitarySpace<D> {
    type Repr = D::Value;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.0.sample(rng)
    }

    fn dim(&self) -> usize {
        1
    }

    fn span(&self) -> Span {
        self.0.span()
    }
}

/// 2-dimensional homogeneous space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct PairSpace<D1, D2>((D1, D2))
    where D1: Dimension,
          D2: Dimension;

impl<D1: Dimension, D2: Dimension> PairSpace<D1, D2> {
    pub fn new(d1: D1, d2: D2) -> Self {
        PairSpace((d1, d2))
    }
}

impl PairSpace<dimensions::Continuous, dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> PairSpace<Partitioned, Partitioned> {
        PairSpace((Partitioned::from_continuous((self.0).0, density),
                   Partitioned::from_continuous((self.0).1, density)))
    }
}

impl<D1: Dimension, D2: Dimension> Space for PairSpace<D1, D2> {
    type Repr = (D1::Value, D2::Value);

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        ((self.0).0.sample(rng), (self.0).1.sample(rng))
    }

    fn dim(&self) -> usize {
        2
    }

    fn span(&self) -> Span {
        (self.0).0.span()*(self.0).1.span()
    }
}

/// N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct RegularSpace<D: Dimension> {
    dimensions: Vec<D>,
    span: Span,
}

impl<D: Dimension> RegularSpace<D> {
    pub fn new(dimensions: Vec<D>) -> Self {
        let mut s = Self::empty();

        for d in dimensions {
            s = s.push(d);
        }

        s
    }

    pub fn empty() -> Self {
        RegularSpace {
            dimensions: vec![],
            span: Span::Null,
        }
    }

    pub fn push(mut self, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.push(d);

        self
    }

    pub fn iter(&self) -> SliceIter<D> {
        self.dimensions.iter()
    }
}

impl RegularSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> RegularSpace<Partitioned> {
        self.into_iter()
            .map(|d| Partitioned::from_continuous(d, density))
            .collect()
    }
}

impl RegularSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .iter()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for RegularSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|d| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<D> for RegularSpace<D> {
    fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for RegularSpace<D> {
    type Item = D;
    type IntoIter = ::std::vec::IntoIter<D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<D> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: D) -> Self::Output {
        self.push(rhs)
    }
}

impl<D: Dimension> Add<RegularSpace<D>> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: RegularSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

/// Named, N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct NamedSpace<D: Dimension> {
    dimensions: HashMap<String, D>,
    span: Span,
}

impl<D: Dimension> NamedSpace<D> {
    pub fn new<S: Into<String>>(dimensions: Vec<(S, D)>) -> Self {
        let mut s = Self::empty();

        for (name, d) in dimensions {
            s = s.push(name, d);
        }

        s
    }

    pub fn empty() -> Self {
        NamedSpace {
            dimensions: HashMap::new(),
            span: Span::Null,
        }
    }

    pub fn push<S: Into<String>>(mut self, name: S, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.insert(name.into(), d);

        self
    }

    pub fn iter(&self) -> HashMapIter<String, D> {
        self.dimensions.iter()
    }
}

impl NamedSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> NamedSpace<Partitioned> {
        self.into_iter()
            .map(|(name, d)| (name, Partitioned::from_continuous(d, density)))
            .collect()
    }
}

impl NamedSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .values()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for NamedSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|(_, d)| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<(String, D)> for NamedSpace<D> {
    fn from_iter<I: IntoIterator<Item = (String, D)>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for NamedSpace<D> {
    type Item = (String, D);
    type IntoIter = ::std::collections::hash_map::IntoIter<String, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<NamedSpace<D>> for NamedSpace<D> {
    type Output = Self;

    fn add(self, rhs: NamedSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

#[cfg(test)]
mod tests {
    use super::{Space, EmptySpace, UnitarySpace, PairSpace, RegularSpace};
    use geometry::Span;
    use geometry::dimensions::*;
    use ndarray::arr1;
    use rand::thread_rng;

    #[test]
    fn test_null_space() {
        let ns = EmptySpace;
        let mut rng = thread_rng();

        assert_eq!(ns.sample(&mut rng), ());
        assert_eq!(ns.dim(), 0);
        assert_eq!(ns.span(), Span::Null);
    }

    #[test]
    fn test_unitary_space() {
        let us = UnitarySpace::new(Discrete::new(2));
        let mut rng = thread_rng();

        let mut counts = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = us.sample(&mut rng);
            counts[sample] += 1.0;

            assert!(sample == 0 || sample == 1);
        }

        assert!((counts/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert_eq!(us.dim(), 1);
        assert_eq!(us.span(), Span::Finite(2));
    }

    #[test]
    fn test_pair_space() {
        let ps = PairSpace::new(Discrete::new(2), Discrete::new(2));

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = ps.sample(&mut rng);

            c1[sample.0] += 1.0;
            c2[sample.1] += 1.0;

            assert!(sample.0 == 0 || sample.0 == 1);
            assert!(sample.1 == 0 || sample.1 == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(ps.dim(), 2);
        assert_eq!(ps.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space() {
        let space = RegularSpace::new(vec![Discrete::new(2); 2]);

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = space.sample(&mut rng);

            c1[sample[0]] += 1.0;
            c2[sample[1]] += 1.0;

            assert!(sample[0] == 0 || sample[0] == 1);
            assert!(sample[1] == 0 || sample[1] == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(space.dim(), 2);
        assert_eq!(space.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space_sugar() {
        let mut sa = RegularSpace::new(vec![Discrete::new(2); 2]);
        let mut sb = RegularSpace::empty() + Discrete::new(2) + Discrete::new(2);

        assert_eq!(sa.dim(), sb.dim());
        assert_eq!(sa.span(), sb.span());

        sa = sa + Discrete::new(3);
        sb = sb + Discrete::new(3);

        assert_eq!(sa.dim(), 3);
        assert_eq!(sa.dim(), sb.dim());

        assert_eq!(sa.span(), Span::Finite(4)*Span::Finite(3));
        assert_eq!(sa.span(), sb.span());
    }
}
<commit_msg>feat(geometry): implement `Index` for `RegularSpace`<commit_after>use super::Span;
use super::dimensions::{self, Dimension, Partitioned};
use rand::ThreadRng;
use std::fmt::Debug;
use std::ops::{Add, Index};
use std::iter::FromIterator;
use std::slice::Iter as SliceIter;
use std::collections::HashMap;
use std::collections::hash_map::Iter as HashMapIter;

/// Trait for defining geometric spaces.
pub trait Space {
    /// The data representation of the space.
    type Repr: Debug + Clone;

    /// Generate a random sample from the space.
    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr;

    /// Return the number of dimensions in the space.
    fn dim(&self) -> usize;

    /// Return the number of linear combinations of values in the space.
    fn span(&self) -> Span;
}

/// Geometric space for agent actions.
///
/// Currently the only supported representation for actions. In future we will need to handle
/// continuous actions.
pub type ActionSpace = UnitarySpace<dimensions::Discrete>;

/// An empty space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct EmptySpace;

impl Space for EmptySpace {
    type Repr = ();

    fn sample(&self, _: &mut ThreadRng) -> Self::Repr {
        ()
    }

    fn dim(&self) -> usize {
        0
    }

    fn span(&self) -> Span {
        Span::Null
    }
}

/// 1-dimensional space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct UnitarySpace<D: Dimension>(D);

impl<D: Dimension> UnitarySpace<D> {
    pub fn new(d: D) -> Self {
        UnitarySpace(d)
    }
}

impl UnitarySpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> UnitarySpace<Partitioned> {
        UnitarySpace(Partitioned::from_continuous(self.0, density))
    }
}

impl<D: Dimension> Space for UnitarySpace<D> {
    type Repr = D::Value;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.0.sample(rng)
    }

    fn dim(&self) -> usize {
        1
    }

    fn span(&self) -> Span {
        self.0.span()
    }
}

/// 2-dimensional homogeneous space.
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct PairSpace<D1, D2>((D1, D2))
    where D1: Dimension,
          D2: Dimension;

impl<D1: Dimension, D2: Dimension> PairSpace<D1, D2> {
    pub fn new(d1: D1, d2: D2) -> Self {
        PairSpace((d1, d2))
    }
}

impl PairSpace<dimensions::Continuous, dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> PairSpace<Partitioned, Partitioned> {
        PairSpace((Partitioned::from_continuous((self.0).0, density),
                   Partitioned::from_continuous((self.0).1, density)))
    }
}

impl<D1: Dimension, D2: Dimension> Space for PairSpace<D1, D2> {
    type Repr = (D1::Value, D2::Value);

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        ((self.0).0.sample(rng), (self.0).1.sample(rng))
    }

    fn dim(&self) -> usize {
        2
    }

    fn span(&self) -> Span {
        (self.0).0.span()*(self.0).1.span()
    }
}

/// N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct RegularSpace<D: Dimension> {
    dimensions: Vec<D>,
    span: Span,
}

impl<D: Dimension> RegularSpace<D> {
    pub fn new(dimensions: Vec<D>) -> Self {
        let mut s = Self::empty();

        for d in dimensions {
            s = s.push(d);
        }

        s
    }

    pub fn empty() -> Self {
        RegularSpace {
            dimensions: vec![],
            span: Span::Null,
        }
    }

    pub fn push(mut self, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.push(d);

        self
    }

    pub fn iter(&self) -> SliceIter<D> {
        self.dimensions.iter()
    }
}

impl RegularSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> RegularSpace<Partitioned> {
        self.into_iter()
            .map(|d| Partitioned::from_continuous(d, density))
            .collect()
    }
}

impl RegularSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .iter()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for RegularSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|d| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<D> for RegularSpace<D> {
    fn from_iter<I: IntoIterator<Item = D>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for RegularSpace<D> {
    type Item = D;
    type IntoIter = ::std::vec::IntoIter<D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<D> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: D) -> Self::Output {
        self.push(rhs)
    }
}

impl<D: Dimension> Add<RegularSpace<D>> for RegularSpace<D> {
    type Output = Self;

    fn add(self, rhs: RegularSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

impl<D: Dimension> Index<usize> for RegularSpace<D> {
    type Output = D;

    fn index(&self, index: usize) -> &D {
        self.dimensions.index(index)
    }
}

/// Named, N-dimensional homogeneous space.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct NamedSpace<D: Dimension> {
    dimensions: HashMap<String, D>,
    span: Span,
}

impl<D: Dimension> NamedSpace<D> {
    pub fn new<S: Into<String>>(dimensions: Vec<(S, D)>) -> Self {
        let mut s = Self::empty();

        for (name, d) in dimensions {
            s = s.push(name, d);
        }

        s
    }

    pub fn empty() -> Self {
        NamedSpace {
            dimensions: HashMap::new(),
            span: Span::Null,
        }
    }

    pub fn push<S: Into<String>>(mut self, name: S, d: D) -> Self {
        self.span = self.span*d.span();
        self.dimensions.insert(name.into(), d);

        self
    }

    pub fn iter(&self) -> HashMapIter<String, D> {
        self.dimensions.iter()
    }
}

impl NamedSpace<dimensions::Continuous> {
    pub fn partitioned(self, density: usize) -> NamedSpace<Partitioned> {
        self.into_iter()
            .map(|(name, d)| (name, Partitioned::from_continuous(d, density)))
            .collect()
    }
}

impl NamedSpace<dimensions::Partitioned> {
    pub fn centres(&self) -> Vec<Vec<f64>> {
        self.dimensions
            .values()
            .map(|d| d.centres())
            .collect()
    }
}

impl<D: Dimension> Space for NamedSpace<D> {
    type Repr = Vec<D::Value>;

    fn sample(&self, rng: &mut ThreadRng) -> Self::Repr {
        self.dimensions.iter().map(|(_, d)| d.sample(rng)).collect()
    }

    fn dim(&self) -> usize {
        self.dimensions.len()
    }

    fn span(&self) -> Span {
        self.span
    }
}

impl<D: Dimension> FromIterator<(String, D)> for NamedSpace<D> {
    fn from_iter<I: IntoIterator<Item = (String, D)>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<D: Dimension> IntoIterator for NamedSpace<D> {
    type Item = (String, D);
    type IntoIter = ::std::collections::hash_map::IntoIter<String, D>;

    fn into_iter(self) -> Self::IntoIter {
        self.dimensions.into_iter()
    }
}

impl<D: Dimension> Add<NamedSpace<D>> for NamedSpace<D> {
    type Output = Self;

    fn add(self, rhs: NamedSpace<D>) -> Self::Output {
        FromIterator::from_iter(self.into_iter().chain(rhs.into_iter()))
    }
}

#[cfg(test)]
mod tests {
    use super::{Space, EmptySpace, UnitarySpace, PairSpace, RegularSpace};
    use geometry::Span;
    use geometry::dimensions::*;
    use ndarray::arr1;
    use rand::thread_rng;

    #[test]
    fn test_null_space() {
        let ns = EmptySpace;
        let mut rng = thread_rng();

        assert_eq!(ns.sample(&mut rng), ());
        assert_eq!(ns.dim(), 0);
        assert_eq!(ns.span(), Span::Null);
    }

    #[test]
    fn test_unitary_space() {
        let us = UnitarySpace::new(Discrete::new(2));
        let mut rng = thread_rng();

        let mut counts = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = us.sample(&mut rng);
            counts[sample] += 1.0;

            assert!(sample == 0 || sample == 1);
        }

        assert!((counts/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert_eq!(us.dim(), 1);
        assert_eq!(us.span(), Span::Finite(2));
    }

    #[test]
    fn test_pair_space() {
        let ps = PairSpace::new(Discrete::new(2), Discrete::new(2));

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = ps.sample(&mut rng);

            c1[sample.0] += 1.0;
            c2[sample.1] += 1.0;

            assert!(sample.0 == 0 || sample.0 == 1);
            assert!(sample.1 == 0 || sample.1 == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(ps.dim(), 2);
        assert_eq!(ps.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space() {
        let space = RegularSpace::new(vec![Discrete::new(2); 2]);

        let mut rng = thread_rng();

        let mut c1 = arr1(&vec![0.0; 2]);
        let mut c2 = arr1(&vec![0.0; 2]);
        for _ in 0..5000 {
            let sample = space.sample(&mut rng);

            c1[sample[0]] += 1.0;
            c2[sample[1]] += 1.0;

            assert!(sample[0] == 0 || sample[0] == 1);
            assert!(sample[1] == 0 || sample[1] == 1);
        }

        assert!((c1/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));
        assert!((c2/5000.0).all_close(&arr1(&vec![0.5; 2]), 1e-1));

        assert_eq!(space.dim(), 2);
        assert_eq!(space.span(), Span::Finite(4));
    }

    #[test]
    fn test_regular_space_sugar() {
        let mut sa = RegularSpace::new(vec![Discrete::new(2); 2]);
        let mut sb = RegularSpace::empty() + Discrete::new(2) + Discrete::new(2);

        assert_eq!(sa.dim(), sb.dim());
        assert_eq!(sa.span(), sb.span());

        sa = sa + Discrete::new(3);
        sb = sb + Discrete::new(3);

        assert_eq!(sa.dim(), 3);
        assert_eq!(sa.dim(), sb.dim());

        assert_eq!(sa.span(), Span::Finite(4)*Span::Finite(3));
        assert_eq!(sa.span(), sb.span());
    }
}
<|endoftext|>


<commit_before>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...
use std::path;

use gfx::format::{Format, Swizzle};
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;
use glam::Quat;

use crate::context::DebugId;
use crate::error::*;
use crate::graphics::*;
use crate::Context;
use crate::{conf, filesystem};

/// A generic canvas independent of graphics backend. This type should
/// never need to be used directly; use [`graphics::Canvas`](type.Canvas.html)
/// instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// [`graphics::set_canvas()`](fn.set_canvas.html) function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `graphics::set_canvas(None)`.
///
/// A `Canvas` allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at
/// [`SpriteBatch`](spritebatch/struct.Spritebatch.html).
///
/// Note that if the canvas is not of the same size as the screen, and you want
/// to render using coordinates relative to the canvas' coordinate system, you
/// need to call [`graphics::set_screen_coordinates`](fn.set_screen_coordinates.html)
/// and pass in a rectangle with position (0, 0) and a size equal to that of the
/// canvas.
///
/// If you draw onto a canvas using BlendMode::Alpha you need to set its blend mode to
/// `BlendMode::Premultiplied` before drawing it to a new surface. This is a side effect
/// of the premultiplication of RGBA values when the canvas was rendered to.
/// This requirement holds for both drawing
/// the `Canvas` directly or converting it to an `Image` first.
/// ```
/// let mut canvas = Canvas::new(width, height, conf::NumSamples::One, get_window_color_format(ctx));
/// graphics::set_canvas(ctx, Some(&canvas));
///
/// // Draw to canvas here...
///
/// graphics::present(ctx);
/// graphics::set_canvas(ctx, None);
/// canvas.set_blend_mode(Some(BlendMode::Premultiplied));
/// ```
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl<S> CanvasGeneric<S>
where
    S: BackendSpec,
{
    #[allow(clippy::new_ret_no_self)]
    /// Create a new `Canvas` with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u16,
        height: u16,
        samples: conf::NumSamples,
        color_format: Format,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s.into()),
        };
        let kind = Kind::D2(width, height, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind,
            levels,
            format: color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(texture_create_info, Some(color_format.1), None)?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new `Canvas` with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use crate::graphics;
        let (w, h) = graphics::drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(
            ctx,
            w as u16,
            h as u16,
            conf::NumSamples::One,
            get_window_color_format(ctx),
        )
    }

    /// Gets the backend `Image` that is being rendered to. Note that this will be flipped but otherwise the same, use the [`to_image`](#method.to_image) function for the unflipped version.
    pub fn raw_image(&self) -> &Image {
        &self.image
    }

    /// Creates an `Image` with the content of its raw counterpart but transformed to behave like a normal `Image`.
    pub fn to_image(&self, ctx: &mut Context) -> GameResult<Image> {
        let pixel_data = self.to_rgba8(ctx)?;
        Image::from_rgba8(ctx, self.image.width, self.image.height, &pixel_data)
    }

    /// Gets the backend `Target` that is being rendered to.
    pub fn target(&self) -> &RawRenderTargetView<S::Resources> {
        &self.target
    }

    /// Dumps the flipped `Canvas`'s data to a `Vec` of `u8` RBGA8 values.
    pub fn to_rgba8(&self, ctx: &mut Context) -> GameResult<Vec<u8>> {
        let mut pixel_data = self.image.to_rgba8(ctx)?;
        flip_pixel_data(
            &mut pixel_data,
            self.image.width as usize,
            self.image.height as usize,
        );
        Ok(pixel_data)
    }

    /// Encode the `Canvas`'s content to the given file format and
    /// write it out to the given path.
    ///
    /// See the [`filesystem`](../filesystem/index.html) module docs for where exactly
    /// the file will end up.
    pub fn encode<P: AsRef<path::Path>>(
        &self,
        ctx: &mut Context,
        format: ImageFormat,
        path: P,
    ) -> GameResult {
        use std::io;
        let data = self.to_rgba8(ctx)?;
        let f = filesystem::create(ctx, path)?;
        let writer = &mut io::BufWriter::new(f);
        let color_format = ::image::ColorType::Rgba8;
        match format {
            ImageFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(
                    &data,
                    u32::from(self.width()),
                    u32::from(self.height()),
                    color_format,
                )
                .map_err(Into::into),
        }
    }

    /// Return the width of the canvas.
    pub fn width(&self) -> u16 {
        self.image.width
    }

    /// Return the height of the canvas.
    pub fn height(&self) -> u16 {
        self.image.height
    }

    /// Returns the dimensions of the canvas.
    pub fn dimensions(&self) -> Rect {
        Rect::new(0.0, 0.0, f32::from(self.width()), f32::from(self.height()))
    }

    /// Get the filter mode for the canvas.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the canvas.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode)
    }
}

impl Drawable for Canvas {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);

        // We have to mess with the scale to make everything
        // be its-unit-size-in-pixels.
        let scale_x = param.src.w * f32::from(self.width());
        let scale_y = param.src.h * f32::from(self.height());

        let param = param.transform(
            glam::Mat4::from(param.trans.to_bare_matrix())
                * Matrix4::from_scale(glam::vec3(scale_x, scale_y, 1.0)),
        );

        let new_param = flip_draw_param_vertical(param);

        image::draw_image_raw(&self.image, ctx, new_param)
    }
    fn dimensions(&self, _: &mut Context) -> Option<Rect> {
        Some(self.image.dimensions())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

fn flip_draw_param_vertical(param: DrawParam) -> DrawParam {
    let param = if let Transform::Matrix(mat) = param.trans {
        param.transform(
            glam::Mat4::from(mat)
                * glam::Mat4::from_scale_rotation_translation(
                    glam::vec3(1.0, -1.0, 1.0),
                    Quat::IDENTITY,
                    glam::vec3(0.0, 1.0, 0.0),
                ),
        )
    } else {
        panic!("Can not be called with a non-matrix DrawParam");
    };
    let new_src = Rect {
        x: param.src.x,
        y: (1.0 - param.src.h) - param.src.y,
        w: param.src.w,
        h: param.src.h,
    };
    param.src(new_src)
}

/// Set the `Canvas` to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<commit_msg>flush the draw command buffer before serializing a canvas<commit_after>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...
use std::path;

use gfx::format::{Format, Swizzle};
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;
use glam::Quat;

use crate::context::DebugId;
use crate::error::*;
use crate::graphics::*;
use crate::Context;
use crate::{conf, filesystem};

/// A generic canvas independent of graphics backend. This type should
/// never need to be used directly; use [`graphics::Canvas`](type.Canvas.html)
/// instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// [`graphics::set_canvas()`](fn.set_canvas.html) function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `graphics::set_canvas(None)`.
///
/// A `Canvas` allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at
/// [`SpriteBatch`](spritebatch/struct.Spritebatch.html).
///
/// Note that if the canvas is not of the same size as the screen, and you want
/// to render using coordinates relative to the canvas' coordinate system, you
/// need to call [`graphics::set_screen_coordinates`](fn.set_screen_coordinates.html)
/// and pass in a rectangle with position (0, 0) and a size equal to that of the
/// canvas.
///
/// If you draw onto a canvas using BlendMode::Alpha you need to set its blend mode to
/// `BlendMode::Premultiplied` before drawing it to a new surface. This is a side effect
/// of the premultiplication of RGBA values when the canvas was rendered to.
/// This requirement holds for both drawing
/// the `Canvas` directly or converting it to an `Image` first.
/// ```
/// let mut canvas = Canvas::new(width, height, conf::NumSamples::One, get_window_color_format(ctx));
/// graphics::set_canvas(ctx, Some(&canvas));
///
/// // Draw to canvas here...
///
/// graphics::present(ctx);
/// graphics::set_canvas(ctx, None);
/// canvas.set_blend_mode(Some(BlendMode::Premultiplied));
/// ```
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl<S> CanvasGeneric<S>
where
    S: BackendSpec,
{
    #[allow(clippy::new_ret_no_self)]
    /// Create a new `Canvas` with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u16,
        height: u16,
        samples: conf::NumSamples,
        color_format: Format,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s.into()),
        };
        let kind = Kind::D2(width, height, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind,
            levels,
            format: color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(texture_create_info, Some(color_format.1), None)?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new `Canvas` with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use crate::graphics;
        let (w, h) = graphics::drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(
            ctx,
            w as u16,
            h as u16,
            conf::NumSamples::One,
            get_window_color_format(ctx),
        )
    }

    /// Gets the backend `Image` that is being rendered to. Note that this will be flipped but otherwise the same, use the [`to_image`](#method.to_image) function for the unflipped version.
    pub fn raw_image(&self) -> &Image {
        &self.image
    }

    /// Creates an `Image` with the content of its raw counterpart but transformed to behave like a normal `Image`.
    pub fn to_image(&self, ctx: &mut Context) -> GameResult<Image> {
        let pixel_data = self.to_rgba8(ctx)?;
        Image::from_rgba8(ctx, self.image.width, self.image.height, &pixel_data)
    }

    /// Gets the backend `Target` that is being rendered to.
    pub fn target(&self) -> &RawRenderTargetView<S::Resources> {
        &self.target
    }

    /// Dumps the flipped `Canvas`'s data to a `Vec` of `u8` RBGA8 values.
    pub fn to_rgba8(&self, ctx: &mut Context) -> GameResult<Vec<u8>> {
        // first flush the command buffer to make sure the canvas is up to date before being serialized
        // fixes https://github.com/ggez/ggez/issues/813
        let gfx = &mut ctx.gfx_context;
        gfx.encoder.flush(&mut *gfx.device);

        let mut pixel_data = self.image.to_rgba8(ctx)?;
        flip_pixel_data(
            &mut pixel_data,
            self.image.width as usize,
            self.image.height as usize,
        );
        Ok(pixel_data)
    }

    /// Encode the `Canvas`'s content to the given file format and
    /// write it out to the given path.
    ///
    /// See the [`filesystem`](../filesystem/index.html) module docs for where exactly
    /// the file will end up.
    pub fn encode<P: AsRef<path::Path>>(
        &self,
        ctx: &mut Context,
        format: ImageFormat,
        path: P,
    ) -> GameResult {
        use std::io;
        let data = self.to_rgba8(ctx)?;
        let f = filesystem::create(ctx, path)?;
        let writer = &mut io::BufWriter::new(f);
        let color_format = ::image::ColorType::Rgba8;
        match format {
            ImageFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(
                    &data,
                    u32::from(self.width()),
                    u32::from(self.height()),
                    color_format,
                )
                .map_err(Into::into),
        }
    }

    /// Return the width of the canvas.
    pub fn width(&self) -> u16 {
        self.image.width
    }

    /// Return the height of the canvas.
    pub fn height(&self) -> u16 {
        self.image.height
    }

    /// Returns the dimensions of the canvas.
    pub fn dimensions(&self) -> Rect {
        Rect::new(0.0, 0.0, f32::from(self.width()), f32::from(self.height()))
    }

    /// Get the filter mode for the canvas.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the canvas.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode)
    }
}

impl Drawable for Canvas {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);

        // We have to mess with the scale to make everything
        // be its-unit-size-in-pixels.
        let scale_x = param.src.w * f32::from(self.width());
        let scale_y = param.src.h * f32::from(self.height());

        let param = param.transform(
            glam::Mat4::from(param.trans.to_bare_matrix())
                * Matrix4::from_scale(glam::vec3(scale_x, scale_y, 1.0)),
        );

        let new_param = flip_draw_param_vertical(param);

        image::draw_image_raw(&self.image, ctx, new_param)
    }
    fn dimensions(&self, _: &mut Context) -> Option<Rect> {
        Some(self.image.dimensions())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

fn flip_draw_param_vertical(param: DrawParam) -> DrawParam {
    let param = if let Transform::Matrix(mat) = param.trans {
        param.transform(
            glam::Mat4::from(mat)
                * glam::Mat4::from_scale_rotation_translation(
                    glam::vec3(1.0, -1.0, 1.0),
                    Quat::IDENTITY,
                    glam::vec3(0.0, 1.0, 0.0),
                ),
        )
    } else {
        panic!("Can not be called with a non-matrix DrawParam");
    };
    let new_src = Rect {
        x: param.src.x,
        y: (1.0 - param.src.h) - param.src.y,
        w: param.src.w,
        h: param.src.h,
    };
    param.src(new_src)
}

/// Set the `Canvas` to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<|endoftext|>


<commit_before>extern crate hyper;

use std::io::Read;
use std::sync::Mutex;

use self::hyper::net::Fresh;
use self::hyper::client::Client;
use self::hyper::header::Connection;
use self::hyper::header::Host;
use self::hyper::server::Handler;
use self::hyper::server::Request;
use self::hyper::server::Response;

use http::app_manager::AppManager;

pub struct Dispatcher {
    pub app_manager: Mutex<AppManager>,
}

impl Dispatcher {
    pub fn new(app_manager: AppManager) -> Dispatcher {
        Dispatcher {
            app_manager: Mutex::new(app_manager),
        }
    }
}

impl Handler for Dispatcher {
    fn handle(&self, request: Request, response: Response<Fresh>) {
        let host: String = request.headers.get::<Host>().unwrap().hostname.to_string();
        let app_name = host.split(".").collect::<Vec<_>>().first().unwrap().to_string();

        let port: u16;
        {
            let mut app_manager = self.app_manager.lock().unwrap();
            port = app_manager.ensure_app_running(&app_name);
        }

        let url = format!("http://localhost:{}", port);

        let client = Client::new();

        let mut app_response = client.get(&url)
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        app_response.read_to_string(&mut body).unwrap();

        response.send(&body.into_bytes()).unwrap();
    }
}
<commit_msg>refactor: Extract Host header parsing logic to a method<commit_after>extern crate hyper;

use std::io::Read;
use std::sync::Mutex;

use self::hyper::net::Fresh;
use self::hyper::client::Client;
use self::hyper::header::Connection;
use self::hyper::header::Host;
use self::hyper::server::Handler;
use self::hyper::server::Request;
use self::hyper::server::Response;

use http::app_manager::AppManager;

pub struct Dispatcher {
    pub app_manager: Mutex<AppManager>,
}

impl Dispatcher {
    pub fn new(app_manager: AppManager) -> Dispatcher {
        Dispatcher {
            app_manager: Mutex::new(app_manager),
        }
    }

    fn ensure_app_running(&self, request: &Request) -> u16 {
        let host = request.headers.get::<Host>().unwrap().hostname.to_string();
        let app_name = host.split(".").collect::<Vec<_>>().first().unwrap().to_string();

        let mut app_manager = self.app_manager.lock().unwrap();

        app_manager.ensure_app_running(&app_name)
    }
}

impl Handler for Dispatcher {
    fn handle(&self, request: Request, response: Response<Fresh>) {
        let port = self.ensure_app_running(&request);

        let url = format!("http://localhost:{}", port);

        let client = Client::new();

        let mut app_response = client.get(&url)
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        app_response.read_to_string(&mut body).unwrap();

        response.send(&body.into_bytes()).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate simple_excel_writer;
use std::io::{Cursor, Read};
use excel::*;
use simple_excel_writer as excel;

fn creates_and_saves_an_excel_sheet_driver(filename: Option<&str>) -> Option<Vec<u8>> {
    let mut wb = if let Some(name) = filename {
        excel::Workbook::create(name)
    } else {
        excel::Workbook::create_in_memory()
    };

    let mut ws = wb.create_sheet("test_sheet");
    ws.add_column(Column { width: 60.0 });
    ws.add_column(Column { width: 30.0 });
    ws.add_column(Column { width: 10.0 });
    ws.add_column(Column { width: 60.0 });
    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Name", "Title", "Success", "Remark"])
            .unwrap();
        sw.append_row(row![
            "Mary",
            "Acountant",
            false,
            r#"<xml><tag>"" & 'World'</tag></xml>"#
        ])
        .unwrap();
        sw.append_row(row![
            "Mary",
            "Programmer",
            true,
            "<xml><tag>\"Hello\" & 'World'</tag></xml>"
        ])
        .unwrap();
        sw.append_row(row!["Marly", "Mary", "Success", "Success", true, 500.])
    })
    .expect("Write excel error!");

    let mut ws = wb.create_sheet("test_sheet<2");

    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Name", "Title", "Success"]).unwrap();
        sw.append_row(row!["Mary", "This", true]).unwrap();

        #[cfg(feature = "chrono")]
        sw.append_row(row![
            chrono::NaiveDate::from_ymd(2020, 10, 15).and_hms(18, 27, 11),
            chrono::NaiveDate::from_ymd(2020, 10, 16)
        ])
        .unwrap();
        Ok(())
    })
    .expect("Write excel error!");

    let mut ws = wb.create_sheet("test_sheet3 is very long and breaks the limit of 31 charcters");

    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Name", "Title", "Success"]).unwrap();
        sw.append_row(row!["Mary", "Sgt Monkey", true])
    })
    .expect("Write excel error!");

    wb.close().expect("Close excel error!")
}

fn get_file_as_str_from_zip(mem_file: &Vec<u8>, file_name: &str) -> String {
    let mut archive = zip::read::ZipArchive::new(Cursor::new(mem_file)).unwrap();
    let mut zip_file = archive.by_name(file_name).unwrap();
    let mut temp_buf = vec![];
    let _ = zip_file.read_to_end(&mut temp_buf).unwrap();
    std::str::from_utf8(&temp_buf[..]).unwrap().to_string()
}

#[test]
fn creates_and_saves_an_excel_sheet() {
    let file_test = creates_and_saves_an_excel_sheet_driver(Some("test.xlsx"));
    assert!(file_test.is_none());

    let in_memory_test = creates_and_saves_an_excel_sheet_driver(None);
    assert!(in_memory_test.is_some());
}

const DEFAULT_STYLE_XML: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
"#;

#[test]
fn creates_file_and_checks_default_style() {
    let mem_file = creates_and_saves_an_excel_sheet_driver(None).unwrap();
    let result = get_file_as_str_from_zip(&mem_file, "xl/styles.xml");
    assert_eq!(DEFAULT_STYLE_XML.to_string(), result, "The style sheet should match!");
}

#[test]
fn creates_file_with_custom_number_format_and_checks_style() {
    let expected_xml = r##"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
"##.to_string();
    let mut wb = excel::Workbook::create_in_memory();
    let dollar_idx = wb.add_cust_number_format("\"$\"#,##0.00".to_string());
    let weight_idx = wb.add_cust_number_format("#,##0.00\" KG\"".to_string());
    let diamond_idx = wb.add_cust_number_format("#,##0.0\"<>\"".to_string());

    assert_eq!(dollar_idx, 3);
    assert_eq!(weight_idx, 4);
    assert_eq!(diamond_idx, 5);

    let mut ws = wb.create_sheet("test_sheet");
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Cost", "Weight", "Symbol"]).expect("Should append header!");
        sw.append_row(row![(20.1, dollar_idx), (50.12, weight_idx), (700.0, diamond_idx)])
    })
    .expect("Write excel error!");

    let mem_file = wb.close().expect("No error on workbook close!").expect("Should have file in memory!");
    let result = get_file_as_str_from_zip(&mem_file, "xl/styles.xml");
    assert_eq!(expected_xml, result, "The style sheet should match!");

    let sheet1 = get_file_as_str_from_zip(&mem_file, "xl/worksheets/sheet1.xml");
    assert!(sheet1.contains(format!("<c r=\"A2\" s=\"{}\"><v>20.1</v></c>", dollar_idx).as_str()), "First cell should reference the 3rd index of the cellXfs list");
    assert!(sheet1.contains(format!("<c r=\"B2\" s=\"{}\"><v>50.12</v></c>", weight_idx).as_str()), "First cell should reference the 4th index of the cellXfs list");
    assert!(sheet1.contains(format!("<c r=\"C2\" s=\"{}\"><v>700</v></c>", diamond_idx).as_str()), "First cell should reference the 5th (last) index of the cellXfs list");
}

#[cfg(feature = "chrono")]
#[test]
fn chrono_check_default_style () {
    let mut wb = excel::Workbook::create_in_memory();
    let mut ws = wb.create_sheet("test_sheet");
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Date", "Datetime"]).expect("Should append header!");
        sw.append_row(row![chrono::NaiveDate::from_ymd(2012, 11, 10), chrono::NaiveDate::from_ymd(2014, 9, 8).and_hms(21, 12, 44)])
    })
    .expect("Write excel error!");

    let mem_file = wb.close().expect("No error on workbook close!").expect("Should have file in memory!");
    let result = get_file_as_str_from_zip(&mem_file, "xl/styles.xml");
    assert_eq!(DEFAULT_STYLE_XML.to_string(), result, "The style sheet should match!");

    let sheet1 = get_file_as_str_from_zip(&mem_file, "xl/worksheets/sheet1.xml");
    let expected_date_format_idx = 1;
    let expected_datetime_format_idx = 2;
    assert!(sheet1.contains(format!("<c r=\"A2\" s=\"{}\"><v>41223</v></c>", expected_date_format_idx).as_str()), "Date contains correct reference to date format");
    assert!(sheet1.contains(format!("<c r=\"B2\" s=\"{}\"><v>41890.88384259259</v></c>", expected_datetime_format_idx).as_str()), "Date contains correct reference to date format");
    use std::io::Write;
    let mut f = std::fs::File::create("test4.xlsx").expect("no issues creating file");
    let _ = f.write_all(&mem_file);
}<commit_msg>Remove file creation in new test (not needed)<commit_after>extern crate simple_excel_writer;
use std::io::{Cursor, Read};
use excel::*;
use simple_excel_writer as excel;

fn creates_and_saves_an_excel_sheet_driver(filename: Option<&str>) -> Option<Vec<u8>> {
    let mut wb = if let Some(name) = filename {
        excel::Workbook::create(name)
    } else {
        excel::Workbook::create_in_memory()
    };

    let mut ws = wb.create_sheet("test_sheet");
    ws.add_column(Column { width: 60.0 });
    ws.add_column(Column { width: 30.0 });
    ws.add_column(Column { width: 10.0 });
    ws.add_column(Column { width: 60.0 });
    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Name", "Title", "Success", "Remark"])
            .unwrap();
        sw.append_row(row![
            "Mary",
            "Acountant",
            false,
            r#"<xml><tag>"" & 'World'</tag></xml>"#
        ])
        .unwrap();
        sw.append_row(row![
            "Mary",
            "Programmer",
            true,
            "<xml><tag>\"Hello\" & 'World'</tag></xml>"
        ])
        .unwrap();
        sw.append_row(row!["Marly", "Mary", "Success", "Success", true, 500.])
    })
    .expect("Write excel error!");

    let mut ws = wb.create_sheet("test_sheet<2");

    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Name", "Title", "Success"]).unwrap();
        sw.append_row(row!["Mary", "This", true]).unwrap();

        #[cfg(feature = "chrono")]
        sw.append_row(row![
            chrono::NaiveDate::from_ymd(2020, 10, 15).and_hms(18, 27, 11),
            chrono::NaiveDate::from_ymd(2020, 10, 16)
        ])
        .unwrap();
        Ok(())
    })
    .expect("Write excel error!");

    let mut ws = wb.create_sheet("test_sheet3 is very long and breaks the limit of 31 charcters");

    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Name", "Title", "Success"]).unwrap();
        sw.append_row(row!["Mary", "Sgt Monkey", true])
    })
    .expect("Write excel error!");

    wb.close().expect("Close excel error!")
}

fn get_file_as_str_from_zip(mem_file: &Vec<u8>, file_name: &str) -> String {
    let mut archive = zip::read::ZipArchive::new(Cursor::new(mem_file)).unwrap();
    let mut zip_file = archive.by_name(file_name).unwrap();
    let mut temp_buf = vec![];
    let _ = zip_file.read_to_end(&mut temp_buf).unwrap();
    std::str::from_utf8(&temp_buf[..]).unwrap().to_string()
}

#[test]
fn creates_and_saves_an_excel_sheet() {
    let file_test = creates_and_saves_an_excel_sheet_driver(Some("test.xlsx"));
    assert!(file_test.is_none());

    let in_memory_test = creates_and_saves_an_excel_sheet_driver(None);
    assert!(in_memory_test.is_some());
}

const DEFAULT_STYLE_XML: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
"#;

#[test]
fn creates_file_and_checks_default_style() {
    let mem_file = creates_and_saves_an_excel_sheet_driver(None).unwrap();
    let result = get_file_as_str_from_zip(&mem_file, "xl/styles.xml");
    assert_eq!(DEFAULT_STYLE_XML.to_string(), result, "The style sheet should match!");
}

#[test]
fn creates_file_with_custom_number_format_and_checks_style() {
    let expected_xml = r##"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
"##.to_string();
    let mut wb = excel::Workbook::create_in_memory();
    let dollar_idx = wb.add_cust_number_format("\"$\"#,##0.00".to_string());
    let weight_idx = wb.add_cust_number_format("#,##0.00\" KG\"".to_string());
    let diamond_idx = wb.add_cust_number_format("#,##0.0\"<>\"".to_string());

    assert_eq!(dollar_idx, 3);
    assert_eq!(weight_idx, 4);
    assert_eq!(diamond_idx, 5);

    let mut ws = wb.create_sheet("test_sheet");
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Cost", "Weight", "Symbol"]).expect("Should append header!");
        sw.append_row(row![(20.1, dollar_idx), (50.12, weight_idx), (700.0, diamond_idx)])
    })
    .expect("Write excel error!");

    let mem_file = wb.close().expect("No error on workbook close!").expect("Should have file in memory!");
    let result = get_file_as_str_from_zip(&mem_file, "xl/styles.xml");
    assert_eq!(expected_xml, result, "The style sheet should match!");

    let sheet1 = get_file_as_str_from_zip(&mem_file, "xl/worksheets/sheet1.xml");
    assert!(sheet1.contains(format!("<c r=\"A2\" s=\"{}\"><v>20.1</v></c>", dollar_idx).as_str()), "First cell should reference the 3rd index of the cellXfs list");
    assert!(sheet1.contains(format!("<c r=\"B2\" s=\"{}\"><v>50.12</v></c>", weight_idx).as_str()), "First cell should reference the 4th index of the cellXfs list");
    assert!(sheet1.contains(format!("<c r=\"C2\" s=\"{}\"><v>700</v></c>", diamond_idx).as_str()), "First cell should reference the 5th (last) index of the cellXfs list");
}

#[cfg(feature = "chrono")]
#[test]
fn chrono_check_default_style () {
    let mut wb = excel::Workbook::create_in_memory();
    let mut ws = wb.create_sheet("test_sheet");
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    ws.add_column(Column { width: 20.0 });
    wb.write_sheet(&mut ws, |sw| {
        sw.append_row(row!["Date", "Datetime"]).expect("Should append header!");
        sw.append_row(row![chrono::NaiveDate::from_ymd(2012, 11, 10), chrono::NaiveDate::from_ymd(2014, 9, 8).and_hms(21, 12, 44)])
    })
    .expect("Write excel error!");

    let mem_file = wb.close().expect("No error on workbook close!").expect("Should have file in memory!");
    let result = get_file_as_str_from_zip(&mem_file, "xl/styles.xml");
    assert_eq!(DEFAULT_STYLE_XML.to_string(), result, "The style sheet should match!");

    let sheet1 = get_file_as_str_from_zip(&mem_file, "xl/worksheets/sheet1.xml");
    let expected_date_format_idx = 1;
    let expected_datetime_format_idx = 2;
    assert!(sheet1.contains(format!("<c r=\"A2\" s=\"{}\"><v>41223</v></c>", expected_date_format_idx).as_str()), "Date contains correct reference to date format");
    assert!(sheet1.contains(format!("<c r=\"B2\" s=\"{}\"><v>41890.88384259259</v></c>", expected_datetime_format_idx).as_str()), "Date contains correct reference to date format");
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use lib::alias_dist::AliasDistribution;
use lib::error::MarkovpassError;

struct MarkovChainIterator<'a> {
    markov_chain: &'a PassphraseMarkovChain,
    current: &'a str,
}

impl<'a> Iterator for MarkovChainIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let last = self.current;
        self.current = self.markov_chain.get_next_ngram(&self.current);

        Some(last)
    }
}

#[derive(Debug)]
struct MarkovNode<T> {
    pub value: T,
    transitions: Vec<T>,
    dist: AliasDistribution,
}

impl<T> MarkovNode<T> {
    pub fn new(value: T, values: Vec<T>, weights: Vec<f64>) -> MarkovNode<T> {
        MarkovNode {
            value: value,
            transitions: values,
            dist: AliasDistribution::new(weights).unwrap(),
        }
    }

    pub fn next(&self) -> &T {
        &self.transitions[self.dist.choice()]
    }

    pub fn entropy(&self) -> f64 {
        self.dist.entropy
    }
}

#[derive(Debug)]
pub struct PassphraseMarkovChain {
    nodes: HashMap<String, MarkovNode<String>>,
    starting_ngrams: Vec<String>,
    starting_dist: AliasDistribution,
}

impl PassphraseMarkovChain {
    pub fn new(ngrams: Vec<String>) -> Result<PassphraseMarkovChain, MarkovpassError> {
        // Count transitions and viable starting ngrams.
        // To get natural sounding words, starting ngrams should be at word start.
        let mut transition_counters: HashMap<String, HashMap<String, usize>> = HashMap::new();
        let mut starting_ngram_counts: HashMap<String, usize> = HashMap::new();

        if ngrams.len() == 0 {
            return Err(MarkovpassError::NoNgrams);
        }
        let mut a = ngrams[0].clone();
        for b in ngrams
            .into_iter()
            .skip(1)
            .chain(Some(a.clone()).into_iter())
        {
            if a.starts_with(" ") {
                *starting_ngram_counts.entry(a.clone()).or_insert(0) += 1;
            }
            *transition_counters
                .entry(a)
                .or_insert(HashMap::new())
                .entry(b.clone())
                .or_insert(0) += 1;
            a = b;
        }

        // Generate the starting ngram probability distribution.
        let mut starting_ngrams = Vec::with_capacity(starting_ngram_counts.len());
        let mut weights = Vec::with_capacity(starting_ngram_counts.len());
        for (value, weight) in starting_ngram_counts.into_iter() {
            starting_ngrams.push(value);
            weights.push(weight as f64);
        }
        let starting_dist = AliasDistribution::new(weights).unwrap();

        // Build all the MarkovNodes from the tranition counts.
        let mut nodes: HashMap<String, MarkovNode<String>> = HashMap::new();
        let mut total_entropy: f64 = 0.0;
        for (ngram, transition_counts) in transition_counters.into_iter() {
            let mut values = Vec::with_capacity(transition_counts.len());
            let mut weights = Vec::with_capacity(transition_counts.len());
            for (value, weight) in transition_counts.into_iter() {
                values.push(value.clone());
                weights.push(weight as f64);
            }

            let node = MarkovNode::new(ngram.clone(), values, weights);
            total_entropy += node.entropy();
            nodes.insert(ngram.to_string(), node);
        }

        if total_entropy == 0.0 {
            return Err(MarkovpassError::NoEntropy);
        } else if starting_dist.entropy == 0.0 {
            return Err(MarkovpassError::NoStartOfWordEntropy);
        };

        Ok(PassphraseMarkovChain {
            nodes: nodes,
            starting_ngrams: starting_ngrams,
            starting_dist: starting_dist,
        })
    }

    pub fn passphrase(&self, min_entropy: f64) -> (String, f64) {
        let mut selected_ngrams = Vec::new();
        let mut entropy = self.starting_dist.entropy;

        for ngram in self.iter() {
            selected_ngrams.push(ngram.clone());
            entropy += self.ngram_entropy(&ngram);
            if entropy >= min_entropy && ngram.ends_with(" ") {
                break;
            }
        }

        // Include the first character from each ngram, and the whole final ngram.
        let tail = selected_ngrams.last().unwrap().chars().skip(1);
        let chars = selected_ngrams
            .iter()
            .map(|n| n.chars().next().unwrap())
            .chain(tail);
        let passphrase = chars.collect::<String>().trim().to_string();

        (passphrase, entropy)
    }

    fn iter(&self) -> MarkovChainIterator {
        MarkovChainIterator {
            markov_chain: &self,
            current: &self.get_starting_ngram(),
        }
    }

    fn get_starting_ngram(&self) -> &str {
        &self.nodes
            .get(&self.starting_ngrams[self.starting_dist.choice()])
            .unwrap()
            .value
    }

    fn get_next_ngram(&self, ngram: &str) -> &str {
        self.nodes.get(ngram).unwrap().next()
    }

    fn ngram_entropy(&self, ngram: &str) -> f64 {
        self.nodes.get(ngram).unwrap().entropy()
    }
}

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

    #[test]
    fn test_passphrasemarkovchain_new() {
        let ngrams = vec![" ti", "tic", "ic ", "c t", " to", "toc", "oc ", "c t"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_ok());
        let chain = result.unwrap();
        assert_eq!(chain.starting_ngrams.len(), 2);
        assert!(chain.starting_ngrams.contains(&" ti".to_string()));
        assert!(chain.starting_ngrams.contains(&" to".to_string()));
        assert_eq!(chain.starting_dist.entropy, 1.0);
        assert!(ngrams.contains(&chain.get_starting_ngram().to_string()));
        let (p, e) = chain.passphrase(60.0);
        assert_eq!(e, 60.0);
        assert_eq!(p.len(), 239);
    }

    #[test]
    fn test_passphrase_no_ngrams() {
        let ngrams: Vec<String> = vec![];
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoNgrams);
    }

    #[test]
    fn test_passphrase_no_entropy() {
        let ngrams = vec![" ab", "abc", "bcd", "cd ", "d a"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoEntropy);
    }

    #[test]
    fn test_passphrases_no_starting_entropy() {
        let ngrams = vec![
            " ab", "abc", "bc ", "c a", " ab", "abc", "cbd", "bd ", "d a"
        ];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoStartOfWordEntropy);
    }
}
<commit_msg>Typo fix<commit_after>use std::collections::HashMap;
use lib::alias_dist::AliasDistribution;
use lib::error::MarkovpassError;

struct MarkovChainIterator<'a> {
    markov_chain: &'a PassphraseMarkovChain,
    current: &'a str,
}

impl<'a> Iterator for MarkovChainIterator<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        let last = self.current;
        self.current = self.markov_chain.get_next_ngram(&self.current);

        Some(last)
    }
}

#[derive(Debug)]
struct MarkovNode<T> {
    pub value: T,
    transitions: Vec<T>,
    dist: AliasDistribution,
}

impl<T> MarkovNode<T> {
    pub fn new(value: T, values: Vec<T>, weights: Vec<f64>) -> MarkovNode<T> {
        MarkovNode {
            value: value,
            transitions: values,
            dist: AliasDistribution::new(weights).unwrap(),
        }
    }

    pub fn next(&self) -> &T {
        &self.transitions[self.dist.choice()]
    }

    pub fn entropy(&self) -> f64 {
        self.dist.entropy
    }
}

#[derive(Debug)]
pub struct PassphraseMarkovChain {
    nodes: HashMap<String, MarkovNode<String>>,
    starting_ngrams: Vec<String>,
    starting_dist: AliasDistribution,
}

impl PassphraseMarkovChain {
    pub fn new(ngrams: Vec<String>) -> Result<PassphraseMarkovChain, MarkovpassError> {
        // Count transitions and viable starting ngrams.
        // To get natural sounding words, starting ngrams should be at word start.
        let mut transition_counters: HashMap<String, HashMap<String, usize>> = HashMap::new();
        let mut starting_ngram_counts: HashMap<String, usize> = HashMap::new();

        if ngrams.len() == 0 {
            return Err(MarkovpassError::NoNgrams);
        }
        let mut a = ngrams[0].clone();
        for b in ngrams
            .into_iter()
            .skip(1)
            .chain(Some(a.clone()).into_iter())
        {
            if a.starts_with(" ") {
                *starting_ngram_counts.entry(a.clone()).or_insert(0) += 1;
            }
            *transition_counters
                .entry(a)
                .or_insert(HashMap::new())
                .entry(b.clone())
                .or_insert(0) += 1;
            a = b;
        }

        // Generate the starting ngram probability distribution.
        let mut starting_ngrams = Vec::with_capacity(starting_ngram_counts.len());
        let mut weights = Vec::with_capacity(starting_ngram_counts.len());
        for (value, weight) in starting_ngram_counts.into_iter() {
            starting_ngrams.push(value);
            weights.push(weight as f64);
        }
        let starting_dist = AliasDistribution::new(weights).unwrap();

        // Build all the MarkovNodes from the transition counts.
        let mut nodes: HashMap<String, MarkovNode<String>> = HashMap::new();
        let mut total_entropy: f64 = 0.0;
        for (ngram, transition_counts) in transition_counters.into_iter() {
            let mut values = Vec::with_capacity(transition_counts.len());
            let mut weights = Vec::with_capacity(transition_counts.len());
            for (value, weight) in transition_counts.into_iter() {
                values.push(value.clone());
                weights.push(weight as f64);
            }

            let node = MarkovNode::new(ngram.clone(), values, weights);
            total_entropy += node.entropy();
            nodes.insert(ngram.to_string(), node);
        }

        if total_entropy == 0.0 {
            return Err(MarkovpassError::NoEntropy);
        } else if starting_dist.entropy == 0.0 {
            return Err(MarkovpassError::NoStartOfWordEntropy);
        };

        Ok(PassphraseMarkovChain {
            nodes: nodes,
            starting_ngrams: starting_ngrams,
            starting_dist: starting_dist,
        })
    }

    pub fn passphrase(&self, min_entropy: f64) -> (String, f64) {
        let mut selected_ngrams = Vec::new();
        let mut entropy = self.starting_dist.entropy;

        for ngram in self.iter() {
            selected_ngrams.push(ngram.clone());
            entropy += self.ngram_entropy(&ngram);
            if entropy >= min_entropy && ngram.ends_with(" ") {
                break;
            }
        }

        // Include the first character from each ngram, and the whole final ngram.
        let tail = selected_ngrams.last().unwrap().chars().skip(1);
        let chars = selected_ngrams
            .iter()
            .map(|n| n.chars().next().unwrap())
            .chain(tail);
        let passphrase = chars.collect::<String>().trim().to_string();

        (passphrase, entropy)
    }

    fn iter(&self) -> MarkovChainIterator {
        MarkovChainIterator {
            markov_chain: &self,
            current: &self.get_starting_ngram(),
        }
    }

    fn get_starting_ngram(&self) -> &str {
        &self.nodes
            .get(&self.starting_ngrams[self.starting_dist.choice()])
            .unwrap()
            .value
    }

    fn get_next_ngram(&self, ngram: &str) -> &str {
        self.nodes.get(ngram).unwrap().next()
    }

    fn ngram_entropy(&self, ngram: &str) -> f64 {
        self.nodes.get(ngram).unwrap().entropy()
    }
}

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

    #[test]
    fn test_passphrasemarkovchain_new() {
        let ngrams = vec![" ti", "tic", "ic ", "c t", " to", "toc", "oc ", "c t"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_ok());
        let chain = result.unwrap();
        assert_eq!(chain.starting_ngrams.len(), 2);
        assert!(chain.starting_ngrams.contains(&" ti".to_string()));
        assert!(chain.starting_ngrams.contains(&" to".to_string()));
        assert_eq!(chain.starting_dist.entropy, 1.0);
        assert!(ngrams.contains(&chain.get_starting_ngram().to_string()));
        let (p, e) = chain.passphrase(60.0);
        assert_eq!(e, 60.0);
        assert_eq!(p.len(), 239);
    }

    #[test]
    fn test_passphrase_no_ngrams() {
        let ngrams: Vec<String> = vec![];
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoNgrams);
    }

    #[test]
    fn test_passphrase_no_entropy() {
        let ngrams = vec![" ab", "abc", "bcd", "cd ", "d a"];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoEntropy);
    }

    #[test]
    fn test_passphrases_no_starting_entropy() {
        let ngrams = vec![
            " ab", "abc", "bc ", "c a", " ab", "abc", "cbd", "bd ", "d a"
        ];
        let ngrams: Vec<String> = ngrams.iter().map(|x| x.to_string()).collect();
        let result = PassphraseMarkovChain::new(ngrams.clone());
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), MarkovpassError::NoStartOfWordEntropy);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions from one type to
//! another. They follow the standard Rust conventions of `as`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to support arguments of
//! multiple types.
//!
//! See each trait for usage examples.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A cheap, reference-to-reference conversion.
///
/// # Examples
///
/// Both `String` and `&str` implement `AsRef<str>`:
///
/// ```
/// fn is_hello<T: AsRef<str>>(s: T) {
///    assert_eq!("hello", s.as_ref());
/// }
///
/// let s = "hello";
/// is_hello(s);
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be expensive.
///
/// # Examples
///
/// `String` implements `Into<Vec<u8>>`:
///
/// ```
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
///    let bytes = b"hello".to_vec();
///    assert_eq!(bytes, s.into());
/// }
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
///
/// # Examples
///
/// `String` implements `From<&str>`:
///
/// ```
/// let s = "hello";
/// let string = "hello".to_string();
///
/// let other_string: String = From::from(s);
///
/// assert_eq!(string, other_string);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    fn as_ref(&self) -> &str {
        self
    }
}
<commit_msg>Rollup merge of #24854 - frewsxcv:patch-19, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions from one type to
//! another. They follow the standard Rust conventions of `as`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to support arguments of
//! multiple types.
//!
//! See each trait for usage examples.

#![stable(feature = "rust1", since = "1.0.0")]

use marker::Sized;

/// A cheap, reference-to-reference conversion.
///
/// # Examples
///
/// Both `String` and `&str` implement `AsRef<str>`:
///
/// ```
/// fn is_hello<T: AsRef<str>>(s: T) {
///    assert_eq!("hello", s.as_ref());
/// }
///
/// let s = "hello";
/// is_hello(s);
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_ref(&self) -> &T;
}

/// A cheap, mutable reference-to-mutable reference conversion.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_mut(&mut self) -> &mut T;
}

/// A conversion that consumes `self`, which may or may not be expensive.
///
/// # Examples
///
/// `String` implements `Into<Vec<u8>>`:
///
/// ```
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
///    let bytes = b"hello".to_vec();
///    assert_eq!(bytes, s.into());
/// }
///
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into(self) -> T;
}

/// Construct `Self` via a conversion.
///
/// # Examples
///
/// `String` implements `From<&str>`:
///
/// ```
/// let string = "hello".to_string();
/// let other_string = String::from("hello");
///
/// assert_eq!(string, other_string);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T> {
    /// Performs the conversion.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from(T) -> Self;
}

////////////////////////////////////////////////////////////////////////////////
// GENERIC IMPLS
////////////////////////////////////////////////////////////////////////////////

// As lifts over &
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// As lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsRef<U> for &'a mut T where T: AsRef<U> {
    fn as_ref(&self) -> &U {
        <T as AsRef<U>>::as_ref(*self)
    }
}

// FIXME (#23442): replace the above impls for &/&mut with the following more general one:
// // As lifts over Deref
// impl<D: ?Sized + Deref, U: ?Sized> AsRef<U> for D where D::Target: AsRef<U> {
//     fn as_ref(&self) -> &U {
//         self.deref().as_ref()
//     }
// }

// AsMut lifts over &mut
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized, U: ?Sized> AsMut<U> for &'a mut T where T: AsMut<U> {
    fn as_mut(&mut self) -> &mut U {
        (*self).as_mut()
    }
}

// FIXME (#23442): replace the above impl for &mut with the following more general one:
// // AsMut lifts over DerefMut
// impl<D: ?Sized + Deref, U: ?Sized> AsMut<U> for D where D::Target: AsMut<U> {
//     fn as_mut(&mut self) -> &mut U {
//         self.deref_mut().as_mut()
//     }
// }

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

////////////////////////////////////////////////////////////////////////////////
// CONCRETE IMPLS
////////////////////////////////////////////////////////////////////////////////

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T] {
    fn as_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<str> for str {
    fn as_ref(&self) -> &str {
        self
    }
}
<|endoftext|>