<commit_before>#![unstable(feature = "wake_trait", issue = "0")]
//! Types and Traits for working with asynchronous tasks.
use core::mem;
use core::task::{Waker, RawWaker, RawWakerVTable};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data
/// used to wake up a task is stored in an [`Arc`]. Some executors (especially
/// those for embedded systems) cannot use this API, which is way [`RawWaker`]
/// exists as an alternative for those systems.
#[unstable(feature = "wake_trait", issue = "0")]
pub trait Wake {
    /// Wake this task.
    #[unstable(feature = "wake_trait", issue = "0")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls `wake` on the clone.
    #[unstable(feature = "wake_trait", issue = "0")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[unstable(feature = "wake_trait", issue = "0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        unsafe {
            Waker::from_raw(raw_waker(waker))
        }
    }
}

#[unstable(feature = "wake_trait", issue = "0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {

    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        mem::forget(waker.clone());
        raw_waker(waker)
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        Wake::wake(waker);
    }

    // Wake by reference, forgetting the Arc to avoid decrementing the reference count
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        Wake::wake_by_ref(&waker);
        mem::forget(waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        mem::drop(Arc::from_raw(waker as *const W));
    }

    RawWaker::new(Arc::into_raw(waker) as *const (), &RawWakerVTable::new(
        clone_waker::<W>,
        wake::<W>,
        wake_by_ref::<W>,
        drop_waker::<W>,
    ))
}
<commit_msg>Improve safety implementation, fix typos<commit_after>#![unstable(feature = "wake_trait", issue = "0")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::{self, ManuallyDrop};
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data
/// used to wake up a task is stored in an [`Arc`]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
#[unstable(feature = "wake_trait", issue = "0")]
pub trait Wake {
    /// Wake this task.
    #[unstable(feature = "wake_trait", issue = "0")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls `wake` on the clone.
    #[unstable(feature = "wake_trait", issue = "0")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[unstable(feature = "wake_trait", issue = "0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[unstable(feature = "wake_trait", issue = "0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        mem::forget(waker.clone());
        raw_waker(waker)
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        Wake::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W));
        Wake::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        mem::drop(Arc::from_raw(waker as *const W));
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    ))
}
<|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.

//! Implementations of things like `Eq` for fixed-length arrays
//! up to a certain length. Eventually we should able to generalize
//! to all lengths.
//!
//! *[See also the array primitive type](../primitive.array.html).*

#![unstable(feature = "fixed_size_array",
            reason = "traits and impls are better expressed through generic \
                      integer constants")]

use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use convert::{AsRef, AsMut};
use fmt;
use hash::{Hash, self};
use iter::IntoIterator;
use marker::{Copy, Sized};
use option::Option;
use slice::{Iter, IterMut, SliceExt};

/// Utility trait implemented only on arrays of fixed size
///
/// This trait can be used to implement other traits on fixed-size arrays
/// without causing much metadata bloat.
pub trait FixedSizeArray<T> {
    /// Converts the array to immutable slice
    fn as_slice(&self) -> &[T];
    /// Converts the array to mutable slice
    fn as_mut_slice(&mut self) -> &mut [T];
}

// macro for implementing n-ary tuple functions and operations
macro_rules! array_impls {
    ($($N:expr)+) => {
        $(
            impl<T> FixedSizeArray<T> for [T; $N] {
                #[inline]
                fn as_slice(&self) -> &[T] {
                    &self[..]
                }
                #[inline]
                fn as_mut_slice(&mut self) -> &mut [T] {
                    &mut self[..]
                }
            }

            impl<T> AsRef<[T]> for [T; $N] {
                #[inline]
                fn as_ref(&self) -> &[T] {
                    &self[..]
                }
            }

            impl<T> AsMut<[T]> for [T; $N] {
                #[inline]
                fn as_mut(&mut self) -> &mut [T] {
                    &mut self[..]
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:Copy> Clone for [T; $N] {
                fn clone(&self) -> [T; $N] {
                    *self
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T: Hash> Hash for [T; $N] {
                fn hash<H: hash::Hasher>(&self, state: &mut H) {
                    Hash::hash(&self[..], state)
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T: fmt::Debug> fmt::Debug for [T; $N] {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    fmt::Debug::fmt(&&self[..], f)
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<'a, T> IntoIterator for &'a [T; $N] {
                type Item = &'a T;
                type IntoIter = Iter<'a, T>;

                fn into_iter(self) -> Iter<'a, T> {
                    self.iter()
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<'a, T> IntoIterator for &'a mut [T; $N] {
                type Item = &'a mut T;
                type IntoIter = IterMut<'a, T>;

                fn into_iter(self) -> IterMut<'a, T> {
                    self.iter_mut()
                }
            }

            // NOTE: some less important impls are omitted to reduce code bloat
            __impl_slice_eq1! { [A; $N], [B; $N] }
            __impl_slice_eq2! { [A; $N], [B] }
            __impl_slice_eq2! { [A; $N], &'b [B] }
            __impl_slice_eq2! { [A; $N], &'b mut [B] }
            // __impl_slice_eq2! { [A; $N], &'b [B; $N] }
            // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:Eq> Eq for [T; $N] { }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:PartialOrd> PartialOrd for [T; $N] {
                #[inline]
                fn partial_cmp(&self, other: &[T; $N]) -> Option<Ordering> {
                    PartialOrd::partial_cmp(&&self[..], &&other[..])
                }
                #[inline]
                fn lt(&self, other: &[T; $N]) -> bool {
                    PartialOrd::lt(&&self[..], &&other[..])
                }
                #[inline]
                fn le(&self, other: &[T; $N]) -> bool {
                    PartialOrd::le(&&self[..], &&other[..])
                }
                #[inline]
                fn ge(&self, other: &[T; $N]) -> bool {
                    PartialOrd::ge(&&self[..], &&other[..])
                }
                #[inline]
                fn gt(&self, other: &[T; $N]) -> bool {
                    PartialOrd::gt(&&self[..], &&other[..])
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:Ord> Ord for [T; $N] {
                #[inline]
                fn cmp(&self, other: &[T; $N]) -> Ordering {
                    Ord::cmp(&&self[..], &&other[..])
                }
            }
        )+
    }
}

array_impls! {
     0  1  2  3  4  5  6  7  8  9
    10 11 12 13 14 15 16 17 18 19
    20 21 22 23 24 25 26 27 28 29
    30 31 32
}
<commit_msg>Auto merge of #27825 - withoutboats:default_array, 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.

//! Implementations of things like `Eq` for fixed-length arrays
//! up to a certain length. Eventually we should able to generalize
//! to all lengths.
//!
//! *[See also the array primitive type](../primitive.array.html).*

#![unstable(feature = "fixed_size_array",
            reason = "traits and impls are better expressed through generic \
                      integer constants")]

use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use convert::{AsRef, AsMut};
use default::Default;
use fmt;
use hash::{Hash, self};
use iter::IntoIterator;
use marker::{Copy, Sized};
use option::Option;
use slice::{Iter, IterMut, SliceExt};

/// Utility trait implemented only on arrays of fixed size
///
/// This trait can be used to implement other traits on fixed-size arrays
/// without causing much metadata bloat.
pub trait FixedSizeArray<T> {
    /// Converts the array to immutable slice
    fn as_slice(&self) -> &[T];
    /// Converts the array to mutable slice
    fn as_mut_slice(&mut self) -> &mut [T];
}

// macro for implementing n-ary tuple functions and operations
macro_rules! array_impls {
    ($($N:expr)+) => {
        $(
            impl<T> FixedSizeArray<T> for [T; $N] {
                #[inline]
                fn as_slice(&self) -> &[T] {
                    &self[..]
                }
                #[inline]
                fn as_mut_slice(&mut self) -> &mut [T] {
                    &mut self[..]
                }
            }

            impl<T> AsRef<[T]> for [T; $N] {
                #[inline]
                fn as_ref(&self) -> &[T] {
                    &self[..]
                }
            }

            impl<T> AsMut<[T]> for [T; $N] {
                #[inline]
                fn as_mut(&mut self) -> &mut [T] {
                    &mut self[..]
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:Copy> Clone for [T; $N] {
                fn clone(&self) -> [T; $N] {
                    *self
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T: Hash> Hash for [T; $N] {
                fn hash<H: hash::Hasher>(&self, state: &mut H) {
                    Hash::hash(&self[..], state)
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T: fmt::Debug> fmt::Debug for [T; $N] {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    fmt::Debug::fmt(&&self[..], f)
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<'a, T> IntoIterator for &'a [T; $N] {
                type Item = &'a T;
                type IntoIter = Iter<'a, T>;

                fn into_iter(self) -> Iter<'a, T> {
                    self.iter()
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<'a, T> IntoIterator for &'a mut [T; $N] {
                type Item = &'a mut T;
                type IntoIter = IterMut<'a, T>;

                fn into_iter(self) -> IterMut<'a, T> {
                    self.iter_mut()
                }
            }

            // NOTE: some less important impls are omitted to reduce code bloat
            __impl_slice_eq1! { [A; $N], [B; $N] }
            __impl_slice_eq2! { [A; $N], [B] }
            __impl_slice_eq2! { [A; $N], &'b [B] }
            __impl_slice_eq2! { [A; $N], &'b mut [B] }
            // __impl_slice_eq2! { [A; $N], &'b [B; $N] }
            // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:Eq> Eq for [T; $N] { }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:PartialOrd> PartialOrd for [T; $N] {
                #[inline]
                fn partial_cmp(&self, other: &[T; $N]) -> Option<Ordering> {
                    PartialOrd::partial_cmp(&&self[..], &&other[..])
                }
                #[inline]
                fn lt(&self, other: &[T; $N]) -> bool {
                    PartialOrd::lt(&&self[..], &&other[..])
                }
                #[inline]
                fn le(&self, other: &[T; $N]) -> bool {
                    PartialOrd::le(&&self[..], &&other[..])
                }
                #[inline]
                fn ge(&self, other: &[T; $N]) -> bool {
                    PartialOrd::ge(&&self[..], &&other[..])
                }
                #[inline]
                fn gt(&self, other: &[T; $N]) -> bool {
                    PartialOrd::gt(&&self[..], &&other[..])
                }
            }

            #[stable(feature = "rust1", since = "1.0.0")]
            impl<T:Ord> Ord for [T; $N] {
                #[inline]
                fn cmp(&self, other: &[T; $N]) -> Ordering {
                    Ord::cmp(&&self[..], &&other[..])
                }
            }
        )+
    }
}

array_impls! {
     0  1  2  3  4  5  6  7  8  9
    10 11 12 13 14 15 16 17 18 19
    20 21 22 23 24 25 26 27 28 29
    30 31 32
}

// The Default impls cannot be generated using the array_impls! macro because
// they require array literals.

macro_rules! array_impl_default {
    {$n:expr, $t:ident $($ts:ident)*} => {
        #[stable(since = "1.4.0", feature = "array_default")]
        impl<T> Default for [T; $n] where T: Default {
            fn default() -> [T; $n] {
                [$t::default(), $($ts::default()),*]
            }
        }
        array_impl_default!{($n - 1), $($ts)*}
    };
    {$n:expr,} => {
        #[stable(since = "1.4.0", feature = "array_default")]
        impl<T> Default for [T; $n] {
            fn default() -> [T; $n] { [] }
        }
    };
}

array_impl_default!{32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

/*!

The `ToStr` trait for converting to strings

*/

use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use container::Map;
use hash::Hash;
use cmp::Eq;
use old_iter::BaseIter;

/// A generic trait for converting a value to a string
pub trait ToStr {
    /// Converts the value of `self` to an owned string
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    /// Cosume and convert to a string.
    fn to_str_consume(self) -> ~str;
}

impl ToStr for () {
    #[inline(always)]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                ~"(" + a.to_str() + ",)"
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |element| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(element.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                ~"(" + a.to_str() + ", " + b.to_str() + ")"
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    use container::Set;
    #[test]
    fn test_simple_types() {
        assert_eq!(1i.to_str(), ~"1");
        assert_eq!((-1i).to_str(), ~"-1");
        assert_eq!(200u.to_str(), ~"200");
        assert_eq!(2u8.to_str(), ~"2");
        assert_eq!(true.to_str(), ~"true");
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(().to_str(), ~"()");
        assert_eq!((~"hi").to_str(), ~"hi");
        assert_eq!((@"hi").to_str(), ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert_eq!((1, 2).to_str(), ~"(1, 2)");
        assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)");
        assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert_eq!(x.to_str(), ~"[]");
        assert_eq!((~[1]).to_str(), ~"[1]");
        assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert_eq!(empty.to_str(), ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert_eq!(empty_set.to_str(), ~"{}");
    }
}
<commit_msg>libstd: use fmt! in to_str impl for (one|two)-tuple<commit_after>// Copyright 2012-2013 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.

/*!

The `ToStr` trait for converting to strings

*/

use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use container::Map;
use hash::Hash;
use cmp::Eq;
use old_iter::BaseIter;

/// A generic trait for converting a value to a string
pub trait ToStr {
    /// Converts the value of `self` to an owned string
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    /// Cosume and convert to a string.
    fn to_str_consume(self) -> ~str;
}

impl ToStr for () {
    #[inline(always)]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                fmt!("(%s,)", (*a).to_str())
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |element| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(element.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                fmt!("(%s, %s)", (*a).to_str(), (*b).to_str())
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline(always)]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.each |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    use container::Set;
    #[test]
    fn test_simple_types() {
        assert_eq!(1i.to_str(), ~"1");
        assert_eq!((-1i).to_str(), ~"-1");
        assert_eq!(200u.to_str(), ~"200");
        assert_eq!(2u8.to_str(), ~"2");
        assert_eq!(true.to_str(), ~"true");
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(().to_str(), ~"()");
        assert_eq!((~"hi").to_str(), ~"hi");
        assert_eq!((@"hi").to_str(), ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert_eq!((1, 2).to_str(), ~"(1, 2)");
        assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)");
        assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert_eq!(x.to_str(), ~"[]");
        assert_eq!((~[1]).to_str(), ~"[1]");
        assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert_eq!(empty.to_str(), ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert_eq!(empty_set.to_str(), ~"{}");
    }
}
<|endoftext|>


<commit_before>//! lint on missing cargo common metadata

use std::path::PathBuf;

use crate::utils::{run_lints, span_lint};
use rustc_hir::{hir_id::CRATE_HIR_ID, Crate};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::DUMMY_SP;

declare_clippy_lint! {
    /// **What it does:** Checks to see if all common metadata is defined in
    /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
    ///
    /// **Why is this bad?** It will be more difficult for users to discover the
    /// purpose of the crate, and key information related to it.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```toml
    /// # This `Cargo.toml` is missing an authors field:
    /// [package]
    /// name = "clippy"
    /// version = "0.0.212"
    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
    /// repository = "https://github.com/rust-lang/rust-clippy"
    /// readme = "README.md"
    /// license = "MIT OR Apache-2.0"
    /// keywords = ["clippy", "lint", "plugin"]
    /// categories = ["development-tools", "development-tools::cargo-plugins"]
    /// ```
    ///
    /// Should include an authors field like:
    ///
    /// ```toml
    /// # This `Cargo.toml` includes all common metadata
    /// [package]
    /// name = "clippy"
    /// version = "0.0.212"
    /// authors = ["Someone <someone@rust-lang.org>"]
    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
    /// repository = "https://github.com/rust-lang/rust-clippy"
    /// readme = "README.md"
    /// license = "MIT OR Apache-2.0"
    /// keywords = ["clippy", "lint", "plugin"]
    /// categories = ["development-tools", "development-tools::cargo-plugins"]
    /// ```
    pub CARGO_COMMON_METADATA,
    cargo,
    "common metadata is defined in `Cargo.toml`"
}

#[derive(Copy, Clone, Debug)]
pub struct CargoCommonMetadata {
    ignore_publish: bool,
}

impl CargoCommonMetadata {
    pub fn new(ignore_publish: bool) -> Self {
        Self { ignore_publish }
    }
}

impl_lint_pass!(CargoCommonMetadata => [
    CARGO_COMMON_METADATA
]);

fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) {
    let message = format!("package `{}` is missing `{}` metadata", package.name, field);
    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
}

fn is_empty_str(value: &Option<String>) -> bool {
    value.as_ref().map_or(true, String::is_empty)
}

fn is_empty_path(value: &Option<PathBuf>) -> bool {
    value.as_ref().and_then(|x| x.to_str()).map_or(true, str::is_empty)
}

fn is_empty_vec(value: &[String]) -> bool {
    // This works because empty iterators return true
    value.iter().all(String::is_empty)
}

impl LateLintPass<'_> for CargoCommonMetadata {
    fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
        if !run_lints(cx, &[CARGO_COMMON_METADATA], CRATE_HIR_ID) {
            return;
        }

        let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false);

        for package in metadata.packages {
            if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish {
                if is_empty_vec(&package.authors) {
                    missing_warning(cx, &package, "package.authors");
                }

                if is_empty_str(&package.description) {
                    missing_warning(cx, &package, "package.description");
                }

                if is_empty_str(&package.license) && is_empty_path(&package.license_file) {
                    missing_warning(cx, &package, "either package.license or package.license_file");
                }

                if is_empty_str(&package.repository) {
                    missing_warning(cx, &package, "package.repository");
                }

                if is_empty_path(&package.readme) {
                    missing_warning(cx, &package, "package.readme");
                }

                if is_empty_vec(&package.keywords) {
                    missing_warning(cx, &package, "package.keywords");
                }

                if is_empty_vec(&package.categories) {
                    missing_warning(cx, &package, "package.categories");
                }
            }
        }
    }
}
<commit_msg>Document condition.<commit_after>//! lint on missing cargo common metadata

use std::path::PathBuf;

use crate::utils::{run_lints, span_lint};
use rustc_hir::{hir_id::CRATE_HIR_ID, Crate};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::DUMMY_SP;

declare_clippy_lint! {
    /// **What it does:** Checks to see if all common metadata is defined in
    /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
    ///
    /// **Why is this bad?** It will be more difficult for users to discover the
    /// purpose of the crate, and key information related to it.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```toml
    /// # This `Cargo.toml` is missing an authors field:
    /// [package]
    /// name = "clippy"
    /// version = "0.0.212"
    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
    /// repository = "https://github.com/rust-lang/rust-clippy"
    /// readme = "README.md"
    /// license = "MIT OR Apache-2.0"
    /// keywords = ["clippy", "lint", "plugin"]
    /// categories = ["development-tools", "development-tools::cargo-plugins"]
    /// ```
    ///
    /// Should include an authors field like:
    ///
    /// ```toml
    /// # This `Cargo.toml` includes all common metadata
    /// [package]
    /// name = "clippy"
    /// version = "0.0.212"
    /// authors = ["Someone <someone@rust-lang.org>"]
    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
    /// repository = "https://github.com/rust-lang/rust-clippy"
    /// readme = "README.md"
    /// license = "MIT OR Apache-2.0"
    /// keywords = ["clippy", "lint", "plugin"]
    /// categories = ["development-tools", "development-tools::cargo-plugins"]
    /// ```
    pub CARGO_COMMON_METADATA,
    cargo,
    "common metadata is defined in `Cargo.toml`"
}

#[derive(Copy, Clone, Debug)]
pub struct CargoCommonMetadata {
    ignore_publish: bool,
}

impl CargoCommonMetadata {
    pub fn new(ignore_publish: bool) -> Self {
        Self { ignore_publish }
    }
}

impl_lint_pass!(CargoCommonMetadata => [
    CARGO_COMMON_METADATA
]);

fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) {
    let message = format!("package `{}` is missing `{}` metadata", package.name, field);
    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
}

fn is_empty_str(value: &Option<String>) -> bool {
    value.as_ref().map_or(true, String::is_empty)
}

fn is_empty_path(value: &Option<PathBuf>) -> bool {
    value.as_ref().and_then(|x| x.to_str()).map_or(true, str::is_empty)
}

fn is_empty_vec(value: &[String]) -> bool {
    // This works because empty iterators return true
    value.iter().all(String::is_empty)
}

impl LateLintPass<'_> for CargoCommonMetadata {
    fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
        if !run_lints(cx, &[CARGO_COMMON_METADATA], CRATE_HIR_ID) {
            return;
        }

        let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false);

        for package in metadata.packages {
            // we want to skip the lint if publish is `None` (`publish = false`) or if the vector is empty (`publish = []`)
            if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish {
                if is_empty_vec(&package.authors) {
                    missing_warning(cx, &package, "package.authors");
                }

                if is_empty_str(&package.description) {
                    missing_warning(cx, &package, "package.description");
                }

                if is_empty_str(&package.license) && is_empty_path(&package.license_file) {
                    missing_warning(cx, &package, "either package.license or package.license_file");
                }

                if is_empty_str(&package.repository) {
                    missing_warning(cx, &package, "package.repository");
                }

                if is_empty_path(&package.readme) {
                    missing_warning(cx, &package, "package.readme");
                }

                if is_empty_vec(&package.keywords) {
                    missing_warning(cx, &package, "package.keywords");
                }

                if is_empty_vec(&package.categories) {
                    missing_warning(cx, &package, "package.categories");
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// This whole file is inspired by: https://github.com/jeaye/q3/blob/master/src/client/ui/ttf/renderer.rs
// available under the BSD-3 licence.
// It has been modified to work with gl-rs, nalgebra, and rust-freetype

use na::{Point2, Point3, Vector2};
use rusttype;
use rusttype::gpu_cache::{Cache, CacheBuilder};
use std::rc::Rc;

use context::{Context, Texture};
use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform};
use text::Font;

#[path = "../error.rs"]
mod error;

struct TextRenderContext {
    len: usize,
    scale: f32,
    color: Point3<f32>,
    pos: Point2<f32>,
    font: Rc<Font>,
}

/// A ttf text renderer.
pub struct TextRenderer {
    text: String,
    texture: Texture,
    shader: Effect,
    cache: Cache<'static>,
    invsz: ShaderUniform<Vector2<f32>>,
    tex: ShaderUniform<i32>,
    color: ShaderUniform<Point3<f32>>,
    pos: ShaderAttribute<Point2<f32>>,
    uvs: ShaderAttribute<Point2<f32>>,
    contexts: Vec<TextRenderContext>,
    coords: GPUVec<Point2<f32>>,
}

impl TextRenderer {
    /// Creates a new text renderer with `font` as the default font.
    pub fn new() -> TextRenderer {
        //
        // Create cache.
        //
        let atlas_width = 1024;
        let atlas_height = 1024;
        let cache = Cache::builder()
            .dimensions(atlas_width, atlas_height)
            .build();

        //
        // Create texture.
        //
        let ctxt = Context::get();

        /* We're using 1 byte alignment buffering. */
        verify!(ctxt.pixel_storei(Context::UNPACK_ALIGNMENT, 1));

        let texture = verify!(
            ctxt.create_texture()
                .expect("Font texture creation failed.")
        );
        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&texture)));
        verify!(ctxt.tex_image2d(
            Context::TEXTURE_2D,
            0,
            Context::RED as i32,
            atlas_width as i32,
            atlas_height as i32,
            0,
            Context::RED,
            None
        ));

        /* Clamp to the edge to avoid artifacts when scaling. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        /* Linear filtering usually looks best for text. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MIN_FILTER,
            Context::LINEAR as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MAG_FILTER,
            Context::LINEAR as i32
        ));

        //
        // Create shader.
        //
        let mut shader = Effect::new_from_str(TEXT_VERTEX_SRC, TEXT_FRAGMENT_SRC);
        shader.use_program();

        TextRenderer {
            text: String::new(),
            cache,
            texture,
            invsz: shader.get_uniform("invsz").expect("Could not find invsz"),
            tex: shader.get_uniform("tex0").expect("Could not find tex0"),
            color: shader.get_uniform("color").expect("Could not find color"),
            pos: shader.get_attrib("pos").expect("Could not find pos"),
            uvs: shader.get_attrib("uvs").expect("Could not find uvs"),
            shader: shader,
            contexts: Vec::new(),
            coords: GPUVec::new(Vec::new(), BufferType::Array, AllocationType::StreamDraw),
        }
    }

    /// Adds a piece of text to be drawn during the next frame. The text is not persistent between
    /// frames. This method must be called for each text to draw, and at each update loop
    /// iteration.
    pub fn draw_text(
        &mut self,
        text: &str,
        pos: &Point2<f32>,
        scale: f32,
        font: &Rc<Font>,
        color: &Point3<f32>,
    ) {
        self.text.push_str(text);
        self.contexts.push(TextRenderContext {
            len: text.len(),
            scale,
            color: *color,
            pos: *pos,
            font: font.clone(),
        })
    }

    /// Actually draws the text.
    pub fn render(&mut self, width: f32, height: f32) {
        if self.contexts.len() == 0 {
            return;
        }

        let ctxt = Context::get();
        self.shader.use_program();

        let _ = verify!(ctxt.polygon_mode(Context::FRONT_AND_BACK, Context::FILL));
        verify!(ctxt.enable(Context::BLEND));
        verify!(ctxt.blend_func(Context::SRC_ALPHA, Context::ONE_MINUS_SRC_ALPHA));
        verify!(ctxt.disable(Context::DEPTH_TEST));

        self.pos.enable();
        self.uvs.enable();
        self.tex.upload(&0);
        self.invsz.upload(&Vector2::new(1.0 / width, -1.0 / height));

        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&self.texture)));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        let mut pos = 0;

        for context in self.contexts.iter() {
            let scale = rusttype::Scale::uniform(context.scale);
            let vmetrics = context.font.font().v_metrics(scale);
            let line_height = vmetrics.ascent - vmetrics.descent;
            let text = &self.text[pos..pos + context.len];
            let font_uid = Font::uid(&context.font);
            let mut vshift = 0.0;

            for line in text.lines() {
                let orig = rusttype::Point {
                    x: context.pos.x,
                    y: context.pos.y + vshift,
                };

                vshift += line_height as f32;
                let layout = context.font.font().layout(line, scale, orig);

                for glyph in layout {
                    let gly: rusttype::PositionedGlyph<'static> = context
                        .font
                        .font()
                        .glyph(glyph.id())
                        .scaled(glyph.scale())
                        .positioned(glyph.position());
                    self.cache.queue_glyph(font_uid, gly); // FIXME: is the call to `.standalone()` costly?
                }

                let _ = self.cache.cache_queued(|rect, data| {
                    verify!(ctxt.tex_sub_image2d(
                        Context::TEXTURE_2D,
                        0,
                        rect.min.x as i32,
                        rect.min.y as i32,
                        rect.width() as i32,
                        rect.height() as i32,
                        Context::RED,
                        Some(&data)
                    ));
                });

                let layout = context.font.font().layout(line, scale, orig);

                {
                    let coords = self.coords.data_mut().as_mut().unwrap();
                    for glyph in layout {
                        if let Some(Some((tex, rect))) = self.cache.rect_for(font_uid, &glyph).ok()
                        {
                            let min_px = rect.min.x as f32;
                            let min_py = rect.min.y as f32 + vmetrics.ascent;
                            let max_px = rect.max.x as f32;
                            let max_py = rect.max.y as f32 + vmetrics.ascent;

                            coords.push(Point2::new(min_px, min_py));
                            coords.push(Point2::new(tex.min.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, max_py));
                            coords.push(Point2::new(tex.max.x, tex.max.y));
                        }
                    }
                }

                self.pos.bind_sub_buffer(&mut self.coords, 1, 0);
                self.uvs.bind_sub_buffer(&mut self.coords, 1, 1);
                self.color.upload(&context.color);

                verify!(ctxt.draw_arrays(Context::TRIANGLES, 0, (self.coords.len() / 2) as i32));
            }
            pos += context.len;

            self.coords.data_mut().as_mut().unwrap().clear();
        }

        self.pos.disable();
        self.uvs.enable();

        verify!(ctxt.enable(Context::DEPTH_TEST));
        verify!(ctxt.disable(Context::BLEND));

        self.contexts.clear();
        self.text.clear();
    }
}

/// Vertex shader used by the material to display line.
pub static TEXT_VERTEX_SRC: &'static str = A_VERY_LONG_STRING;
/// Fragment shader used by the material to display line.
pub static TEXT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

const A_VERY_LONG_STRING: &'static str = "
#version 100

uniform vec2 invsz;
uniform vec3 color;

attribute vec2 pos;
attribute vec2 uvs;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_Position = vec4(pos.x * invsz.x - 1.0, pos.y * invsz.y + 1.0, -1.0, 1.0);
    tex         = uvs;
    Color       = color;
}
";

const ANOTHER_VERY_LONG_STRING: &'static str = "
#version 100

#ifdef GL_FRAGMENT_PRECISION_HIGH
   precision highp float;
#else
   precision mediump float;
#endif

uniform sampler2D tex0;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_FragColor = vec4(Color, texture2D(tex0, tex).r);
}
";
<commit_msg>Removed an import which was no more needed after version update<commit_after>// This whole file is inspired by: https://github.com/jeaye/q3/blob/master/src/client/ui/ttf/renderer.rs
// available under the BSD-3 licence.
// It has been modified to work with gl-rs, nalgebra, and rust-freetype

use na::{Point2, Point3, Vector2};
use rusttype;
use rusttype::gpu_cache::Cache;
use std::rc::Rc;

use context::{Context, Texture};
use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform};
use text::Font;

#[path = "../error.rs"]
mod error;

struct TextRenderContext {
    len: usize,
    scale: f32,
    color: Point3<f32>,
    pos: Point2<f32>,
    font: Rc<Font>,
}

/// A ttf text renderer.
pub struct TextRenderer {
    text: String,
    texture: Texture,
    shader: Effect,
    cache: Cache<'static>,
    invsz: ShaderUniform<Vector2<f32>>,
    tex: ShaderUniform<i32>,
    color: ShaderUniform<Point3<f32>>,
    pos: ShaderAttribute<Point2<f32>>,
    uvs: ShaderAttribute<Point2<f32>>,
    contexts: Vec<TextRenderContext>,
    coords: GPUVec<Point2<f32>>,
}

impl TextRenderer {
    /// Creates a new text renderer with `font` as the default font.
    pub fn new() -> TextRenderer {
        //
        // Create cache.
        //
        let atlas_width = 1024;
        let atlas_height = 1024;
        let cache = Cache::builder()
            .dimensions(atlas_width, atlas_height)
            .build();

        //
        // Create texture.
        //
        let ctxt = Context::get();

        /* We're using 1 byte alignment buffering. */
        verify!(ctxt.pixel_storei(Context::UNPACK_ALIGNMENT, 1));

        let texture = verify!(
            ctxt.create_texture()
                .expect("Font texture creation failed.")
        );
        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&texture)));
        verify!(ctxt.tex_image2d(
            Context::TEXTURE_2D,
            0,
            Context::RED as i32,
            atlas_width as i32,
            atlas_height as i32,
            0,
            Context::RED,
            None
        ));

        /* Clamp to the edge to avoid artifacts when scaling. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        /* Linear filtering usually looks best for text. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MIN_FILTER,
            Context::LINEAR as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MAG_FILTER,
            Context::LINEAR as i32
        ));

        //
        // Create shader.
        //
        let mut shader = Effect::new_from_str(TEXT_VERTEX_SRC, TEXT_FRAGMENT_SRC);
        shader.use_program();

        TextRenderer {
            text: String::new(),
            cache,
            texture,
            invsz: shader.get_uniform("invsz").expect("Could not find invsz"),
            tex: shader.get_uniform("tex0").expect("Could not find tex0"),
            color: shader.get_uniform("color").expect("Could not find color"),
            pos: shader.get_attrib("pos").expect("Could not find pos"),
            uvs: shader.get_attrib("uvs").expect("Could not find uvs"),
            shader: shader,
            contexts: Vec::new(),
            coords: GPUVec::new(Vec::new(), BufferType::Array, AllocationType::StreamDraw),
        }
    }

    /// Adds a piece of text to be drawn during the next frame. The text is not persistent between
    /// frames. This method must be called for each text to draw, and at each update loop
    /// iteration.
    pub fn draw_text(
        &mut self,
        text: &str,
        pos: &Point2<f32>,
        scale: f32,
        font: &Rc<Font>,
        color: &Point3<f32>,
    ) {
        self.text.push_str(text);
        self.contexts.push(TextRenderContext {
            len: text.len(),
            scale,
            color: *color,
            pos: *pos,
            font: font.clone(),
        })
    }

    /// Actually draws the text.
    pub fn render(&mut self, width: f32, height: f32) {
        if self.contexts.len() == 0 {
            return;
        }

        let ctxt = Context::get();
        self.shader.use_program();

        let _ = verify!(ctxt.polygon_mode(Context::FRONT_AND_BACK, Context::FILL));
        verify!(ctxt.enable(Context::BLEND));
        verify!(ctxt.blend_func(Context::SRC_ALPHA, Context::ONE_MINUS_SRC_ALPHA));
        verify!(ctxt.disable(Context::DEPTH_TEST));

        self.pos.enable();
        self.uvs.enable();
        self.tex.upload(&0);
        self.invsz.upload(&Vector2::new(1.0 / width, -1.0 / height));

        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&self.texture)));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        let mut pos = 0;

        for context in self.contexts.iter() {
            let scale = rusttype::Scale::uniform(context.scale);
            let vmetrics = context.font.font().v_metrics(scale);
            let line_height = vmetrics.ascent - vmetrics.descent;
            let text = &self.text[pos..pos + context.len];
            let font_uid = Font::uid(&context.font);
            let mut vshift = 0.0;

            for line in text.lines() {
                let orig = rusttype::Point {
                    x: context.pos.x,
                    y: context.pos.y + vshift,
                };

                vshift += line_height as f32;
                let layout = context.font.font().layout(line, scale, orig);

                for glyph in layout {
                    let gly: rusttype::PositionedGlyph<'static> = context
                        .font
                        .font()
                        .glyph(glyph.id())
                        .scaled(glyph.scale())
                        .positioned(glyph.position());
                    self.cache.queue_glyph(font_uid, gly); // FIXME: is the call to `.standalone()` costly?
                }

                let _ = self.cache.cache_queued(|rect, data| {
                    verify!(ctxt.tex_sub_image2d(
                        Context::TEXTURE_2D,
                        0,
                        rect.min.x as i32,
                        rect.min.y as i32,
                        rect.width() as i32,
                        rect.height() as i32,
                        Context::RED,
                        Some(&data)
                    ));
                });

                let layout = context.font.font().layout(line, scale, orig);

                {
                    let coords = self.coords.data_mut().as_mut().unwrap();
                    for glyph in layout {
                        if let Some(Some((tex, rect))) = self.cache.rect_for(font_uid, &glyph).ok()
                        {
                            let min_px = rect.min.x as f32;
                            let min_py = rect.min.y as f32 + vmetrics.ascent;
                            let max_px = rect.max.x as f32;
                            let max_py = rect.max.y as f32 + vmetrics.ascent;

                            coords.push(Point2::new(min_px, min_py));
                            coords.push(Point2::new(tex.min.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, max_py));
                            coords.push(Point2::new(tex.max.x, tex.max.y));
                        }
                    }
                }

                self.pos.bind_sub_buffer(&mut self.coords, 1, 0);
                self.uvs.bind_sub_buffer(&mut self.coords, 1, 1);
                self.color.upload(&context.color);

                verify!(ctxt.draw_arrays(Context::TRIANGLES, 0, (self.coords.len() / 2) as i32));
            }
            pos += context.len;

            self.coords.data_mut().as_mut().unwrap().clear();
        }

        self.pos.disable();
        self.uvs.enable();

        verify!(ctxt.enable(Context::DEPTH_TEST));
        verify!(ctxt.disable(Context::BLEND));

        self.contexts.clear();
        self.text.clear();
    }
}

/// Vertex shader used by the material to display line.
pub static TEXT_VERTEX_SRC: &'static str = A_VERY_LONG_STRING;
/// Fragment shader used by the material to display line.
pub static TEXT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

const A_VERY_LONG_STRING: &'static str = "
#version 100

uniform vec2 invsz;
uniform vec3 color;

attribute vec2 pos;
attribute vec2 uvs;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_Position = vec4(pos.x * invsz.x - 1.0, pos.y * invsz.y + 1.0, -1.0, 1.0);
    tex         = uvs;
    Color       = color;
}
";

const ANOTHER_VERY_LONG_STRING: &'static str = "
#version 100

#ifdef GL_FRAGMENT_PRECISION_HIGH
   precision highp float;
#else
   precision mediump float;
#endif

uniform sampler2D tex0;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_FragColor = vec4(Color, texture2D(tex0, tex).r);
}
";
<|endoftext|>


<commit_before>use libc::c_void;

use std::ffi::CString;

use tree::{ParseOption, ParseResult, Encoding, ParseStatus, FormatOption};

use tree::NodeBase;

use wrapper::*;

pub enum CDocument {}

pub struct Document {
    ptr: *mut CDocument,
}

impl NodeBase for Document {
    fn get_ptr(&self) -> *mut c_void {
        self.ptr as *mut c_void
    }
}

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

impl Document {
    fn new() -> Result<Self, ParseResult> {
        let document = unsafe { pugi_new_document() };
        if document.is_null() {
            Err(ParseResult::default())
        } else {
            Ok(Document { ptr: document })
        }
    }
}

#[derive(PartialEq)]
enum DataType {
    File,
    String,
    None,
}

pub struct DocumentBuilder {
    parse_options: Vec<ParseOption>,
    encoding: Encoding,
    data_type: DataType,
    data: String,
}

impl DocumentBuilder {
    pub fn new() -> DocumentBuilder {
        DocumentBuilder {
            parse_options: vec![],
            encoding: Encoding::Auto,
            data_type: DataType::None,
            data: String::new(),
        }
    }

    pub fn from_file(mut self, path: &str) -> DocumentBuilder {
        self.data_type = DataType::File;
        self.data = path.to_string();
        self
    }

    pub fn from_string(mut self, string: &str) -> DocumentBuilder {
        self.data_type = DataType::String;
        self.data = string.to_string();
        self
    }

    pub fn encoded_in(mut self, encoding: Encoding) -> DocumentBuilder {
        self.encoding = encoding;
        self
    }

    pub fn with_parse_option(mut self, parse_option: ParseOption) -> DocumentBuilder {
        self.parse_options.push(parse_option);
        self
    }

    pub fn finish(&self) -> Result<Document, ParseResult> {
        let combined_parse_options = if self.parse_options.is_empty() {
            ParseOption::Default
        } else {
            self.parse_options
                .iter()
                .fold(ParseOption::RawValue(0), |acc, x| acc | *x)
        };
        let c_data = CString::new(&self.data as &str).unwrap();

        let document = try!(Document::new());

        match self.data_type {
            DataType::File => {
                match ParseResult::new(unsafe {
                    pugi_load_file(document.ptr,
                                   c_data.as_ptr(),
                                   combined_parse_options.value(),
                                   self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::String => {
                match ParseResult::new(unsafe {
                    pugi_load_buffer(document.ptr,
                                     c_data.as_ptr(),
                                     self.data.len(),
                                     combined_parse_options.value(),
                                     self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::None => Document::new(),
        }
    }
}

    pub fn save_file(self, path: &str, indent_string: &str, format_options: Vec<FormatOption>,
                     encoding: Encoding)
        -> Result<Self, ()> {
        let combined_format_options = format_options.iter()
            .fold(FormatOption::RawValue(0), |acc, x| acc | *x);
        let c_path = CString::new(path).unwrap();
        let c_indent_string = CString::new(indent_string).unwrap();
pub fn reset_with(document: Document, other: &Document) -> Result<Document, ()> {
    unsafe {
        pugi_reset_document_with(document.ptr, other.ptr);
    }
    Ok(document)
}

        unsafe {
            match pugi_save_file(self.doc_ptr,
                                 c_path.as_ptr(),
                                 c_indent_string.as_ptr(),
                                 combined_format_options.value(),
                                 encoding) {
                1 => Ok(self),
                _ => Err(()),
            }
        }
    }
}
<commit_msg>Updating save_file function in Document<commit_after>use libc::c_void;

use std::ffi::CString;

use tree::{ParseOption, ParseResult, Encoding, ParseStatus, FormatOption};

use tree::NodeBase;

use wrapper::*;

pub enum CDocument {}

pub struct Document {
    ptr: *mut CDocument,
}

impl NodeBase for Document {
    fn get_ptr(&self) -> *mut c_void {
        self.ptr as *mut c_void
    }
}

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

impl Document {
    fn new() -> Result<Self, ParseResult> {
        let document = unsafe { pugi_new_document() };
        if document.is_null() {
            Err(ParseResult::default())
        } else {
            Ok(Document { ptr: document })
        }
    }
}

#[derive(PartialEq)]
enum DataType {
    File,
    String,
    None,
}

pub struct DocumentBuilder {
    parse_options: Vec<ParseOption>,
    encoding: Encoding,
    data_type: DataType,
    data: String,
}

impl DocumentBuilder {
    pub fn new() -> DocumentBuilder {
        DocumentBuilder {
            parse_options: vec![],
            encoding: Encoding::Auto,
            data_type: DataType::None,
            data: String::new(),
        }
    }

    pub fn from_file(mut self, path: &str) -> DocumentBuilder {
        self.data_type = DataType::File;
        self.data = path.to_string();
        self
    }

    pub fn from_string(mut self, string: &str) -> DocumentBuilder {
        self.data_type = DataType::String;
        self.data = string.to_string();
        self
    }

    pub fn encoded_in(mut self, encoding: Encoding) -> DocumentBuilder {
        self.encoding = encoding;
        self
    }

    pub fn with_parse_option(mut self, parse_option: ParseOption) -> DocumentBuilder {
        self.parse_options.push(parse_option);
        self
    }

    pub fn finish(&self) -> Result<Document, ParseResult> {
        let combined_parse_options = if self.parse_options.is_empty() {
            ParseOption::Default
        } else {
            self.parse_options
                .iter()
                .fold(ParseOption::RawValue(0), |acc, x| acc | *x)
        };
        let c_data = CString::new(&self.data as &str).unwrap();

        let document = try!(Document::new());

        match self.data_type {
            DataType::File => {
                match ParseResult::new(unsafe {
                    pugi_load_file(document.ptr,
                                   c_data.as_ptr(),
                                   combined_parse_options.value(),
                                   self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::String => {
                match ParseResult::new(unsafe {
                    pugi_load_buffer(document.ptr,
                                     c_data.as_ptr(),
                                     self.data.len(),
                                     combined_parse_options.value(),
                                     self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::None => Document::new(),
        }
    }
}

pub fn reset_with(document: Document, other: &Document) -> Result<Document, ()> {
    unsafe {
        pugi_reset_document_with(document.ptr, other.ptr);
    }
    Ok(document)
}

pub fn to_file(document: &Document, path: &str, indent_string: &str,
               format_options: Vec<FormatOption>, encoding: Encoding)
    -> bool {
    let combined_format_options = format_options.iter()
        .fold(FormatOption::RawValue(0), |acc, x| acc | *x);
    let c_path = CString::new(path).unwrap();
    let c_indent_string = CString::new(indent_string).unwrap();

    match unsafe {
        pugi_save_file(document.ptr,
                       c_path.as_ptr(),
                       c_indent_string.as_ptr(),
                       combined_format_options.value(),
                       encoding)
    } {
        1 => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>pub mod bindings;
pub mod compiler;
pub mod error;
pub mod load;
pub mod patch;
pub mod program;

use crate::compiler::data::{compile_data_initializers, compile_sparse_page_data};
use crate::compiler::function::compile_function;
use crate::compiler::globals::compile_global_specs;
use crate::compiler::memory::compile_memory_specs;
use crate::compiler::module_data::compile_module_data;
use crate::compiler::table::compile_table;
use crate::error::{LucetcError, LucetcErrorKind};
use crate::load::read_module;
use crate::patch::patch_module;
use crate::program::Program;
use failure::{format_err, Error, ResultExt};
use parity_wasm::elements::Module;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tempfile;

pub use crate::{
    bindings::Bindings,
    compiler::{Compiler, OptLevel},
    program::memory::HeapSettings,
};

pub struct Lucetc {
    module: Module,
    name: String,
    bindings: Bindings,
    opt_level: OptLevel,
    heap: HeapSettings,
    builtins_path: Option<PathBuf>,
}

/*
*/

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: P) -> Result<Self, LucetcError> {
        let input = input.as_ref();
        let module = read_module(input)?;
        let name = String::from(
            input
                .file_stem()
                .ok_or(format_err!("input filename {:?} is not a file", input))?
                .to_str()
                .ok_or(format_err!("input filename {:?} is not valid utf8", input))?,
        );
        Ok(Self {
            module,
            name,
            bindings: Bindings::empty(),
            opt_level: OptLevel::default(),
            heap: HeapSettings::default(),
            builtins_path: None,
        })
    }

    pub fn bindings(mut self, bindings: Bindings) -> Result<Self, Error> {
        self.with_bindings(bindings)?;
        Ok(self)
    }
    pub fn with_bindings(&mut self, bindings: Bindings) -> Result<(), Error> {
        self.bindings.extend(bindings)
    }

    pub fn opt_level(mut self, opt_level: OptLevel) -> Self {
        self.with_opt_level(opt_level);
        self
    }
    pub fn with_opt_level(&mut self, opt_level: OptLevel) {
        self.opt_level = opt_level;
    }

    pub fn builtins<P: AsRef<Path>>(mut self, builtins: P) -> Result<Self, Error> {
        self.with_builtins(builtins)?;
        Ok(self)
    }
    pub fn with_builtins<P: AsRef<Path>>(&mut self, builtins_path: P) -> Result<(), Error> {
        let (newmodule, builtins_map) = patch_module(self.module.clone(), builtins_path)?;
        self.module = newmodule;
        self.bindings.extend(Bindings::env(builtins_map))?;
        Ok(())
    }

    pub fn min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.with_min_reserved_size(min_reserved_size);
        self
    }
    pub fn with_min_reserved_size(&mut self, min_reserved_size: u64) {
        self.heap.min_reserved_size = min_reserved_size;
    }

    pub fn max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.with_max_reserved_size(max_reserved_size);
        self
    }
    pub fn with_max_reserved_size(&mut self, max_reserved_size: u64) {
        self.heap.max_reserved_size = max_reserved_size;
    }

    pub fn guard_size(mut self, guard_size: u64) -> Self {
        self.with_guard_size(guard_size);
        self
    }
    pub fn with_guard_size(&mut self, guard_size: u64) {
        self.heap.guard_size = guard_size;
    }

    pub fn object_file<P: AsRef<Path>>(self, output: P) -> Result<(), Error> {
        let prog = Program::new(self.module, self.bindings, self.heap.clone())?;
        let comp = compile(&prog, &self.name, self.opt_level)?;

        let obj = comp.codegen()?;
        obj.write(output.as_ref()).context("writing object file")?;

        Ok(())
    }

    pub fn clif_ir<P: AsRef<Path>>(self, output: P) -> Result<(), Error> {
        let (module, builtins_map) = if let Some(ref builtins_path) = self.builtins_path {
            patch_module(self.module, builtins_path)?
        } else {
            (self.module, HashMap::new())
        };

        let mut bindings = self.bindings.clone();
        bindings.extend(Bindings::env(builtins_map))?;

        let prog = Program::new(module, bindings, self.heap.clone())?;
        let comp = compile(&prog, &self.name, self.opt_level)?;

        comp.cranelift_funcs()
            .write(&output)
            .context("writing clif file")?;

        Ok(())
    }

    pub fn shared_object_file<P: AsRef<Path>>(self, output: P) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(objpath, output)?;
        Ok(())
    }
}

fn link_so<P, Q>(objpath: P, sopath: Q) -> Result<(), Error>
where
    P: AsRef<Path>,
    Q: AsRef<Path>,
{
    use std::process::Command;
    let mut cmd_ld = Command::new("ld");
    cmd_ld.arg(objpath.as_ref());
    cmd_ld.arg("-shared");
    cmd_ld.arg("-o");
    cmd_ld.arg(sopath.as_ref());

    let run_ld = cmd_ld
        .output()
        .context(format_err!("running ld on {:?}", objpath.as_ref()))?;

    if !run_ld.status.success() {
        Err(format_err!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        ))?;
    }
    Ok(())
}

pub fn compile<'p>(
    program: &'p Program,
    name: &str,
    opt_level: OptLevel,
) -> Result<Compiler<'p>, LucetcError> {
    let mut compiler = Compiler::new(name.to_owned(), &program, opt_level)?;

    compile_data_initializers(&mut compiler).context(LucetcErrorKind::DataInitializers)?;
    compile_sparse_page_data(&mut compiler).context(LucetcErrorKind::DataInitializers)?;
    compile_memory_specs(&mut compiler).context(LucetcErrorKind::MemorySpecs)?;
    compile_global_specs(&mut compiler).context(LucetcErrorKind::GlobalSpecs)?;
    compile_module_data(&mut compiler).context(LucetcErrorKind::ModuleData)?;

    for function in program.defined_functions() {
        let body = program.function_body(&function);
        compile_function(&mut compiler, &function, body)
            .context(LucetcErrorKind::Function(function.symbol().to_owned()))?;
    }
    for table in program.tables() {
        compile_table(&mut compiler, &table)
            .context(LucetcErrorKind::Table(table.symbol().to_owned()))?;
    }

    Ok(compiler)
}
<commit_msg>Make lucetc work on macOS<commit_after>pub mod bindings;
pub mod compiler;
pub mod error;
pub mod load;
pub mod patch;
pub mod program;

use crate::compiler::data::{compile_data_initializers, compile_sparse_page_data};
use crate::compiler::function::compile_function;
use crate::compiler::globals::compile_global_specs;
use crate::compiler::memory::compile_memory_specs;
use crate::compiler::module_data::compile_module_data;
use crate::compiler::table::compile_table;
use crate::error::{LucetcError, LucetcErrorKind};
use crate::load::read_module;
use crate::patch::patch_module;
use crate::program::Program;
use failure::{format_err, Error, ResultExt};
use parity_wasm::elements::Module;
use std::collections::HashMap;
use std::env;
use std::path::{Path, PathBuf};
use tempfile;

pub use crate::{
    bindings::Bindings,
    compiler::{Compiler, OptLevel},
    program::memory::HeapSettings,
};

pub struct Lucetc {
    module: Module,
    name: String,
    bindings: Bindings,
    opt_level: OptLevel,
    heap: HeapSettings,
    builtins_path: Option<PathBuf>,
}

/*
*/

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: P) -> Result<Self, LucetcError> {
        let input = input.as_ref();
        let module = read_module(input)?;
        let name = String::from(
            input
                .file_stem()
                .ok_or(format_err!("input filename {:?} is not a file", input))?
                .to_str()
                .ok_or(format_err!("input filename {:?} is not valid utf8", input))?,
        );
        Ok(Self {
            module,
            name,
            bindings: Bindings::empty(),
            opt_level: OptLevel::default(),
            heap: HeapSettings::default(),
            builtins_path: None,
        })
    }

    pub fn bindings(mut self, bindings: Bindings) -> Result<Self, Error> {
        self.with_bindings(bindings)?;
        Ok(self)
    }
    pub fn with_bindings(&mut self, bindings: Bindings) -> Result<(), Error> {
        self.bindings.extend(bindings)
    }

    pub fn opt_level(mut self, opt_level: OptLevel) -> Self {
        self.with_opt_level(opt_level);
        self
    }
    pub fn with_opt_level(&mut self, opt_level: OptLevel) {
        self.opt_level = opt_level;
    }

    pub fn builtins<P: AsRef<Path>>(mut self, builtins: P) -> Result<Self, Error> {
        self.with_builtins(builtins)?;
        Ok(self)
    }
    pub fn with_builtins<P: AsRef<Path>>(&mut self, builtins_path: P) -> Result<(), Error> {
        let (newmodule, builtins_map) = patch_module(self.module.clone(), builtins_path)?;
        self.module = newmodule;
        self.bindings.extend(Bindings::env(builtins_map))?;
        Ok(())
    }

    pub fn min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.with_min_reserved_size(min_reserved_size);
        self
    }
    pub fn with_min_reserved_size(&mut self, min_reserved_size: u64) {
        self.heap.min_reserved_size = min_reserved_size;
    }

    pub fn max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.with_max_reserved_size(max_reserved_size);
        self
    }
    pub fn with_max_reserved_size(&mut self, max_reserved_size: u64) {
        self.heap.max_reserved_size = max_reserved_size;
    }

    pub fn guard_size(mut self, guard_size: u64) -> Self {
        self.with_guard_size(guard_size);
        self
    }
    pub fn with_guard_size(&mut self, guard_size: u64) {
        self.heap.guard_size = guard_size;
    }

    pub fn object_file<P: AsRef<Path>>(self, output: P) -> Result<(), Error> {
        let prog = Program::new(self.module, self.bindings, self.heap.clone())?;
        let comp = compile(&prog, &self.name, self.opt_level)?;

        let obj = comp.codegen()?;
        obj.write(output.as_ref()).context("writing object file")?;

        Ok(())
    }

    pub fn clif_ir<P: AsRef<Path>>(self, output: P) -> Result<(), Error> {
        let (module, builtins_map) = if let Some(ref builtins_path) = self.builtins_path {
            patch_module(self.module, builtins_path)?
        } else {
            (self.module, HashMap::new())
        };

        let mut bindings = self.bindings.clone();
        bindings.extend(Bindings::env(builtins_map))?;

        let prog = Program::new(module, bindings, self.heap.clone())?;
        let comp = compile(&prog, &self.name, self.opt_level)?;

        comp.cranelift_funcs()
            .write(&output)
            .context("writing clif file")?;

        Ok(())
    }

    pub fn shared_object_file<P: AsRef<Path>>(self, output: P) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(objpath, output)?;
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

#[cfg(not(target_os = "macos"))]
const LDFLAGS_DEFAULT: &str = "-shared";

#[cfg(target_os = "macos")]
const LDFLAGS_DEFAULT: &str = "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup";

fn link_so<P, Q>(objpath: P, sopath: Q) -> Result<(), Error>
where
    P: AsRef<Path>,
    Q: AsRef<Path>,
{
    use std::process::Command;
    let mut cmd_ld = Command::new(env::var("LD").unwrap_or(LD_DEFAULT.into()));
    cmd_ld.arg(objpath.as_ref());
    let env_ldflags = env::var("LDFLAGS").unwrap_or(LDFLAGS_DEFAULT.into());
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }
    cmd_ld.arg("-o");
    cmd_ld.arg(sopath.as_ref());

    let run_ld = cmd_ld
        .output()
        .context(format_err!("running ld on {:?}", objpath.as_ref()))?;

    if !run_ld.status.success() {
        Err(format_err!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        ))?;
    }
    Ok(())
}

pub fn compile<'p>(
    program: &'p Program,
    name: &str,
    opt_level: OptLevel,
) -> Result<Compiler<'p>, LucetcError> {
    let mut compiler = Compiler::new(name.to_owned(), &program, opt_level)?;

    compile_data_initializers(&mut compiler).context(LucetcErrorKind::DataInitializers)?;
    compile_sparse_page_data(&mut compiler).context(LucetcErrorKind::DataInitializers)?;
    compile_memory_specs(&mut compiler).context(LucetcErrorKind::MemorySpecs)?;
    compile_global_specs(&mut compiler).context(LucetcErrorKind::GlobalSpecs)?;
    compile_module_data(&mut compiler).context(LucetcErrorKind::ModuleData)?;

    for function in program.defined_functions() {
        let body = program.function_body(&function);
        compile_function(&mut compiler, &function, body)
            .context(LucetcErrorKind::Function(function.symbol().to_owned()))?;
    }
    for table in program.tables() {
        compile_table(&mut compiler, &table)
            .context(LucetcErrorKind::Table(table.symbol().to_owned()))?;
    }

    Ok(compiler)
}
<|endoftext|>


<commit_before>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

#![crate_name="html5ever_macros"]
#![crate_type="dylib"]

#![feature(plugin_registrar, quote, old_orphan_check)]
#![feature(rustc_private, std_misc, core, hash, collections, path, io)]
#![deny(warnings)]

extern crate syntax;
extern crate rustc;
extern crate "serialize" as rustc_serialize;

use rustc::plugin::Registry;

// Internal macros for use in defining other macros.
#[macro_use]
mod internal;

// Make these public so that rustdoc will generate documentation for them.
pub mod named_entities;
pub mod match_token;

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("named_entities", named_entities::expand);
    reg.register_macro("match_token", match_token::expand);
}
<commit_msg>Remove old orphan check<commit_after>// Copyright 2014 The html5ever Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

#![crate_name="html5ever_macros"]
#![crate_type="dylib"]

#![feature(plugin_registrar, quote)]
#![feature(rustc_private, std_misc, core, hash, collections, path, io)]
#![deny(warnings)]

extern crate syntax;
extern crate rustc;
extern crate "serialize" as rustc_serialize;

use rustc::plugin::Registry;

// Internal macros for use in defining other macros.
#[macro_use]
mod internal;

// Make these public so that rustdoc will generate documentation for them.
pub mod named_entities;
pub mod match_token;

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("named_entities", named_entities::expand);
    reg.register_macro("match_token", match_token::expand);
}
<|endoftext|>