<commit_before>use std::marker::PhantomData;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use num::Zero;
use num_iter::{Range, range};
use super::*;
use arith::{self, Equal, Less, LessEqual};

/// Represents a value less than `'l`.
///
/// Semantically equivalent to:
/// `exists<'i> (Less<Val<'i, usize>, Val<'l, usize>>, Val<'i, usize>)`.
///
/// In the future, `Ix` will be changed to a more transparent implementation
/// using `Exists` whenever the ICEs get fixed.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ix<'l> {
    len: PhantomData<Val<'l, usize>>,
    inner: usize,
}

impl<'l> Ix<'l> {
    pub fn new<'i>(index: Val<'i, usize>,
                   _: Less<Val<'i, usize>, Val<'l, usize>>)
                   -> Self {
        Ix { len: PhantomData, inner: index.value() }
    }

    pub fn try_new(index: usize, len: Val<'l, usize>) -> Option<Self> {
        imprint(index, |i| {
            match arith::compare(&i, &len) {
                Ok(lt) => Some(Self::new(i, lt)),
                Err(_) => None,
            }
        })
    }

    pub fn with<F, R>(self, callback: F) -> R
        where F: for<'i> FnOnce(Val<'i, usize>,
                                Less<Val<'i, usize>, Val<'l, usize>>) -> R {
        callback(unsafe { Val::known(self.inner) },
                 unsafe { Less::conjure() })
    }

    pub fn convert<'m>(self, le: LessEqual<Val<'l, usize>, Val<'m, usize>>)
                     -> Ix<'m> {
        self.with(|i, self_lt| Ix::new(i, self_lt.rcomp_le(le)))
    }

    pub unsafe fn from_raw(index: usize) -> Self {
        imprint(index, |i| {
            Ix::new(i, Less::conjure())
        })
    }

    pub fn into_inner(self) -> usize {
        self.inner
    }
}

impl<'i> fmt::Debug for Ix<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Ix(")?;
        (*self).fmt(f)?;
        f.write_str(")")
    }
}

impl<'l> AsRef<usize> for Ix<'l> {
    fn as_ref(&self) -> &usize {
        &**self
    }
}

impl<'l> Borrow<usize> for Ix<'l> {
    fn borrow(&self) -> &usize {
        &**self
    }
}

impl<'l> Deref for Ix<'l> {
    type Target = usize;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

/// An owned variant of `Sl`.
pub struct BoxedSl<'l, T> {
    len: PhantomData<Val<'l, usize>>,
    inner: Box<[T]>,
}

impl<'l, T> BoxedSl<'l, T> {
    pub fn from_boxed_slice(boxed_slice: Box<[T]>, len: Val<'l, usize>)
                            -> Result<Self, Box<[T]>> {
        if boxed_slice.len() == len.value() {
            Ok(unsafe { Self::from_raw(boxed_slice) })
        } else {
            Err(boxed_slice)
        }
    }

    pub fn new(len: Val<'l, usize>, value: T) -> Self where T: Clone {
        unsafe { Self::from_raw(
            vec![value; len.value()].into_boxed_slice()
        ) }
    }

    pub unsafe fn from_raw(boxed_slice: Box<[T]>) -> Self {
        BoxedSl {
            len: PhantomData,
            inner: boxed_slice,
        }
    }

    pub fn len(&self) -> Val<'l, usize> {
        unsafe { Val::known((**self).len()) }
    }

    pub fn as_slice<'a>(&'a self) -> Sl<'a, 'l, T> {
        unsafe { Sl::from_raw((**self).as_ptr()) }
    }

    pub fn as_mut_slice<'a>(&'a mut self) -> MutSl<'a, 'l, T> {
        unsafe { MutSl::from_raw((**self).as_mut_ptr()) }
    }

    pub fn into_inner(self) -> Box<[T]> {
        self.inner
    }
}

impl<'l, T> Deref for BoxedSl<'l, T> {
    type Target = Box<[T]>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'l, T> DerefMut for BoxedSl<'l, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<'a, 'l, T: fmt::Debug> fmt::Debug for BoxedSl<'l, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("BoxedSl(")?;
        self.inner.fmt(f)?;
        f.write_str(")")
    }
}

impl<'l, T> Index<Ix<'l>> for BoxedSl<'l, T> {
    type Output = T;
    fn index(&self, index: Ix<'l>) -> &Self::Output {
        // can't use Sl impl because we aren't using unsized types!
        unsafe { self.inner.get_unchecked(*index) }
    }
}

impl<'l, T> IndexMut<Ix<'l>> for BoxedSl<'l, T> {
    fn index_mut<'a>(&'a mut self, index: Ix<'l>) -> &'a mut Self::Output {
        // can't use MutSl impl because we aren't using unsized types!
        unsafe { self.inner.get_unchecked_mut(*index) }
    }
}

/// An immutable slice.
#[derive(Clone, Copy)]
pub struct Sl<'a, 'l, T: 'a> {
    len: PhantomData<(Val<'l, usize>, &'a T)>,
    ptr: *const T,
}

impl<'a, 'l, T> Sl<'a, 'l, T> {
    pub fn from_slice(slice: &'a [T], len: Val<'l, usize>) -> Option<Self> {
        if slice.len() == len.value() {
            Some(unsafe { Self::from_raw(slice.as_ptr()) })
        } else {
            None
        }
    }

    pub unsafe fn from_raw(ptr: *const T) -> Self {
        Sl { len: PhantomData, ptr: ptr }
    }

    pub fn as_ptr(self) -> *const T {
        self.ptr
    }

    pub fn as_slice(self, len: Val<'l, usize>) -> &'a [T] {
        use std::slice;
        unsafe { slice::from_raw_parts(self.as_ptr(), len.value()) }
    }
}

impl<'a, 'l, T> fmt::Debug for Sl<'a, 'l, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Sl(")?;
        // we can't print the contents without knowledge of its size :/
        self.ptr.fmt(f)?;
        f.write_str(")")
    }
}

impl<'a, 'l, T> Index<Ix<'l>> for Sl<'a, 'l, T> {
    type Output = T;
    fn index(&self, index: Ix<'l>) -> &Self::Output {
        unsafe { &*self.ptr.offset(*index as isize) }
    }
}

/// A mutable variant of `Sl`.
pub struct MutSl<'a, 'l, T: 'a> {
    len: PhantomData<(Val<'l, usize>, &'a mut T)>,
    ptr: *mut T,
}

impl<'a, 'l, T> MutSl<'a, 'l, T> {
    pub fn from_slice(slice: &'a mut [T], len: Val<'l, usize>)
                      -> Option<Self> {
        if slice.len() == len.value() {
            Some(unsafe { Self::from_raw(slice.as_mut_ptr()) })
        } else {
            None
        }
    }

    pub fn as_slice<'b>(&'b self, len: Val<'l, usize>) -> &'b [T] {
        use std::slice;
        unsafe { slice::from_raw_parts_mut(self.ptr, len.value()) }
    }

    pub fn into_slice(self, len: Val<'l, usize>) -> &'a mut [T] {
        use std::slice;
        unsafe { slice::from_raw_parts_mut(self.ptr, len.value()) }
    }

    pub unsafe fn from_raw(ptr: *mut T) -> Self {
        MutSl { len: PhantomData, ptr: ptr }
    }

    pub fn as_ptr(self) -> *const T {
        self.ptr
    }

    pub fn as_mut_ptr(self) -> *mut T {
        self.ptr
    }
}

impl<'a, 'l, T> fmt::Debug for MutSl<'a, 'l, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("MutSl(")?;
        // we can't print the contents without knowledge of its size :/
        self.ptr.fmt(f)?;
        f.write_str(")")
    }
}

impl<'a, 'l, T> Index<Ix<'l>> for MutSl<'a, 'l, T> {
    type Output = T;
    fn index(&self, index: Ix<'l>) -> &Self::Output {
        unsafe { &*self.ptr.offset(*index as isize) }
    }
}

impl<'a, 'l, T> IndexMut<Ix<'l>> for MutSl<'a, 'l, T> {
    fn index_mut(&mut self, index: Ix<'l>) -> &mut Self::Output {
        unsafe { &mut *self.ptr.offset(*index as isize) }
    }
}

#[derive(Clone)]
pub struct IxRange<'l> {
    len: PhantomData<Val<'l, usize>>,
    inner: Range<usize>,
}

impl<'l> IxRange<'l> {
    pub fn new_with<'i>(start: usize, stop: Val<'i, usize>,
                        _: LessEqual<Val<'i, usize>, Val<'l, usize>>) -> Self {
        IxRange {
            len: PhantomData,
            inner: range(start, stop.value()),
        }
    }

    /// `[start .. stop)`
    pub fn new(start: usize, stop: Ix<'l>) -> Self {
        stop.with(|i, lt| {
            Self::new_with(start, i, LessEqual::from(lt))
        })
    }

    /// `[0 .. stop)`
    pub fn new_to(stop: Ix<'l>) -> Self {
        Self::new(Zero::zero(), stop)
    }

    /// `[start ... stop]`
    pub fn new_inclusive(start: usize, stop_inclusive: Ix<'l>) -> Self {
        stop_inclusive.with(|i, lt| {
            arith::succ(&i, lt, |i_plus_1, _, le| {
                Self::new_with(start, i_plus_1, le)
            })
        })
    }

    /// `[0 .. stop]`
    pub fn new_to_inclusive(stop_inclusive: Ix<'l>) -> Self {
        Self::new_inclusive(Zero::zero(), stop_inclusive)
    }

    /// `[start .. len)`
    pub fn new_from(start: usize, len: Val<'l, usize>) -> Self {
        Self::new_with(start, len, LessEqual::from(Equal::refl()))
    }

    /// `[0 .. len)`
    pub fn new_full(len: Val<'l, usize>) -> Self {
        Self::new_from(Zero::zero(), len)
    }
}

impl<'l> Deref for IxRange<'l> {
    type Target = Range<usize>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'l> DerefMut for IxRange<'l> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<'l> Iterator for IxRange<'l> {
    type Item = Ix<'l>;

    fn next(&mut self) -> Option<Self::Item> {
        (**self).next().map(|i| unsafe { Ix::from_raw(i) })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (**self).size_hint()
    }
}

impl<'l> DoubleEndedIterator for IxRange<'l> {
    fn next_back(&mut self) -> Option<Self::Item> {
        (**self).next_back().map(|i| unsafe { Ix::from_raw(i) })
    }
}

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

    #[test]
    fn it_works() {
        let n_ = 42;
        imprint(n_, |n| {
            let vec: Vec<usize> = (0 .. n_).collect();
            let slice = Sl::from_slice(&vec, n).unwrap();
            let mut a = BoxedSl::new(n, 0.0);
            let mut b = BoxedSl::new(n, 0.0);
            for i in IxRange::new_full(n) {
                let i_ = *i;
                a[i] = i_ as f64 * 0.5;
                b[i] = (n_ - i_) as f64;
            }
            for i in IxRange::new_full(n) {
                let i_ = *i;
                assert_eq!(slice[i], i_);
                assert_eq!(a[i], i_ as f64 * 0.5);
                assert_eq!(b[i], (n_ - i_) as f64);
            }
        })
    }
}
<commit_msg>Update src/ix.rs<commit_after>use std::marker::PhantomData;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use num::Zero;
use num_iter::{Range, range};
use super::*;
use arith::{self, Equal, Less, LessEqual};

/// Represents a value less than `'l`.
///
/// Semantically equivalent to:
/// `exists<'i> (Less<Val<'i, usize>, Val<'l, usize>>, Val<'i, usize>)`.
///
/// In the future, `Ix` will be changed to a more transparent implementation
/// using `Exists` whenever the ICEs get fixed.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ix<'l> {
    len: PhantomData<Val<'l, usize>>,
    inner: usize,
}

impl<'l> Ix<'l> {
    pub fn new<'i>(index: Val<'i, usize>,
                   _: Less<Val<'i, usize>, Val<'l, usize>>)
                   -> Self {
        Ix { len: PhantomData, inner: index.value() }
    }

    pub fn try_new(index: usize, len: Val<'l, usize>) -> Option<Self> {
        imprint(index, |i| {
            match arith::compare(&i, &len) {
                Ok(lt) => Some(Self::new(i, lt)),
                Err(_) => None,
            }
        })
    }

    pub fn with<F, R>(self, callback: F) -> R
        where F: for<'i> FnOnce(Val<'i, usize>,
                                Less<Val<'i, usize>, Val<'l, usize>>) -> R {
        callback(unsafe { Val::known(self.inner) },
                 unsafe { Less::conjure() })
    }

    pub fn convert<'m>(self, le: LessEqual<Val<'l, usize>, Val<'m, usize>>)
                     -> Ix<'m> {
        self.with(|i, self_lt| Ix::new(i, self_lt.rcomp_le(le)))
    }

    pub unsafe fn from_raw(index: usize) -> Self {
        imprint(index, |i| {
            Ix::new(i, Less::conjure())
        })
    }

    pub fn into_inner(self) -> usize {
        self.inner
    }
}

impl<'i> fmt::Debug for Ix<'i> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Ix(")?;
        (*self).fmt(f)?;
        f.write_str(")")
    }
}

impl<'l> AsRef<usize> for Ix<'l> {
    fn as_ref(&self) -> &usize {
        &**self
    }
}

impl<'l> Borrow<usize> for Ix<'l> {
    fn borrow(&self) -> &usize {
        &**self
    }
}

impl<'l> Deref for Ix<'l> {
    type Target = usize;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

/// An owned variant of `Sl`.
pub struct BoxedSl<'l, T> {
    len: PhantomData<Val<'l, usize>>,
    inner: Box<[T]>,
}

impl<'l, T> BoxedSl<'l, T> {
    pub fn from_boxed_slice(boxed_slice: Box<[T]>, len: Val<'l, usize>)
                            -> Result<Self, Box<[T]>> {
        if boxed_slice.len() == len.value() {
            Ok(unsafe { Self::from_raw(boxed_slice) })
        } else {
            Err(boxed_slice)
        }
    }

    pub fn new(len: Val<'l, usize>, value: T) -> Self where T: Clone {
        unsafe { Self::from_raw(
            vec![value; len.value()].into_boxed_slice()
        ) }
    }

    pub unsafe fn from_raw(boxed_slice: Box<[T]>) -> Self {
        BoxedSl {
            len: PhantomData,
            inner: boxed_slice,
        }
    }

    pub fn len(&self) -> Val<'l, usize> {
        unsafe { Val::known((**self).len()) }
    }

    pub fn as_sl<'a>(&'a self) -> Sl<'a, 'l, T> {
        unsafe { Sl::from_raw((**self).as_ptr()) }
    }

    pub fn as_mut_sl<'a>(&'a mut self) -> MutSl<'a, 'l, T> {
        unsafe { MutSl::from_raw((**self).as_mut_ptr()) }
    }

    pub fn into_inner(self) -> Box<[T]> {
        self.inner
    }
}

impl<'l, T> Deref for BoxedSl<'l, T> {
    type Target = Box<[T]>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'l, T> DerefMut for BoxedSl<'l, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<'a, 'l, T: fmt::Debug> fmt::Debug for BoxedSl<'l, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("BoxedSl(")?;
        self.inner.fmt(f)?;
        f.write_str(")")
    }
}

impl<'l, T> Index<Ix<'l>> for BoxedSl<'l, T> {
    type Output = T;
    fn index(&self, index: Ix<'l>) -> &Self::Output {
        self.as_sl().get(index)
    }
}

impl<'l, T> IndexMut<Ix<'l>> for BoxedSl<'l, T> {
    fn index_mut<'a>(&'a mut self, index: Ix<'l>) -> &'a mut Self::Output {
        self.as_mut_sl().get_mut(index)
    }
}

/// An immutable slice.
pub struct Sl<'a, 'l, T: 'a> {
    len: PhantomData<(Val<'l, usize>, &'a T)>,
    ptr: *const T,
}

impl<'a, 'l, T> Clone for Sl<'a, 'l, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, 'l, T> Copy for Sl<'a, 'l, T> {}

impl<'a, 'l, T> Sl<'a, 'l, T> {
    pub fn from_slice(slice: &'a [T], len: Val<'l, usize>) -> Option<Self> {
        if slice.len() == len.value() {
            Some(unsafe { Self::from_raw(slice.as_ptr()) })
        } else {
            None
        }
    }

    pub unsafe fn from_raw(ptr: *const T) -> Self {
        Sl { len: PhantomData, ptr: ptr }
    }

    fn get(self, index: Ix<'l>) -> &'a T {
        unsafe { &*self.ptr.offset(*index as isize) }
    }

    pub fn into_ptr(self) -> *const T {
        self.ptr
    }

    pub fn into_slice(self, len: Val<'l, usize>) -> &'a [T] {
        use std::slice;
        unsafe { slice::from_raw_parts(self.into_ptr(), len.value()) }
    }
}

impl<'a, 'l, T> fmt::Debug for Sl<'a, 'l, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Sl(")?;
        // we can't print the contents without knowledge of its size :/
        self.ptr.fmt(f)?;
        f.write_str(")")
    }
}

impl<'a, 'l, T> Index<Ix<'l>> for Sl<'a, 'l, T> {
    type Output = T;
    fn index(&self, index: Ix<'l>) -> &Self::Output {
        self.get(index)
    }
}

/// A mutable variant of `Sl`.
pub struct MutSl<'a, 'l, T: 'a> {
    len: PhantomData<(Val<'l, usize>, &'a mut T)>,
    ptr: *mut T,
}

impl<'a, 'l, T> MutSl<'a, 'l, T> {
    pub fn from_slice(slice: &'a mut [T], len: Val<'l, usize>)
                      -> Option<Self> {
        if slice.len() == len.value() {
            Some(unsafe { Self::from_raw(slice.as_mut_ptr()) })
        } else {
            None
        }
    }

    pub fn as_sl<'b>(&'b self) -> Sl<'b, 'l, T> {
        unsafe { Sl::from_raw(self.ptr) }
    }

    pub fn as_slice(&self, len: Val<'l, usize>) -> &[T] {
        use std::slice;
        unsafe { slice::from_raw_parts_mut(self.ptr, len.value()) }
    }

    pub fn into_mut_slice(self, len: Val<'l, usize>) -> &'a mut [T] {
        use std::slice;
        unsafe { slice::from_raw_parts_mut(self.ptr, len.value()) }
    }

    pub unsafe fn from_raw(ptr: *mut T) -> Self {
        MutSl { len: PhantomData, ptr: ptr }
    }

    fn get_mut(&mut self, index: Ix<'l>) -> &'a mut T {
        unsafe { &mut *self.ptr.offset(*index as isize) }
    }

    pub fn into_ptr(self) -> *const T {
        self.ptr
    }

    pub fn into_mut_ptr(self) -> *mut T {
        self.ptr
    }
}

impl<'a, 'l, T> fmt::Debug for MutSl<'a, 'l, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("MutSl(")?;
        // we can't print the contents without knowledge of its size :/
        self.ptr.fmt(f)?;
        f.write_str(")")
    }
}

impl<'a, 'l, T> Index<Ix<'l>> for MutSl<'a, 'l, T> {
    type Output = T;
    fn index(&self, index: Ix<'l>) -> &Self::Output {
        self.as_sl().get(index)
    }
}

impl<'a, 'l, T> IndexMut<Ix<'l>> for MutSl<'a, 'l, T> {
    fn index_mut(&mut self, index: Ix<'l>) -> &mut Self::Output {
        self.get_mut(index)
    }
}

#[derive(Clone)]
pub struct IxRange<'l> {
    len: PhantomData<Val<'l, usize>>,
    inner: Range<usize>,
}

impl<'l> IxRange<'l> {
    pub fn new_with<'i>(start: usize, stop: Val<'i, usize>,
                        _: LessEqual<Val<'i, usize>, Val<'l, usize>>) -> Self {
        IxRange {
            len: PhantomData,
            inner: range(start, stop.value()),
        }
    }

    /// `[start .. stop)`
    pub fn new(start: usize, stop: Ix<'l>) -> Self {
        stop.with(|i, lt| {
            Self::new_with(start, i, LessEqual::from(lt))
        })
    }

    /// `[0 .. stop)`
    pub fn new_to(stop: Ix<'l>) -> Self {
        Self::new(Zero::zero(), stop)
    }

    /// `[start ... stop]`
    pub fn new_inclusive(start: usize, stop_inclusive: Ix<'l>) -> Self {
        stop_inclusive.with(|i, lt| {
            arith::succ(&i, lt, |i_plus_1, _, le| {
                Self::new_with(start, i_plus_1, le)
            })
        })
    }

    /// `[0 .. stop]`
    pub fn new_to_inclusive(stop_inclusive: Ix<'l>) -> Self {
        Self::new_inclusive(Zero::zero(), stop_inclusive)
    }

    /// `[start .. len)`
    pub fn new_from(start: usize, len: Val<'l, usize>) -> Self {
        Self::new_with(start, len, LessEqual::from(Equal::refl()))
    }

    /// `[0 .. len)`
    pub fn new_full(len: Val<'l, usize>) -> Self {
        Self::new_from(Zero::zero(), len)
    }
}

impl<'l> Deref for IxRange<'l> {
    type Target = Range<usize>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'l> DerefMut for IxRange<'l> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<'l> Iterator for IxRange<'l> {
    type Item = Ix<'l>;

    fn next(&mut self) -> Option<Self::Item> {
        (**self).next().map(|i| unsafe { Ix::from_raw(i) })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (**self).size_hint()
    }
}

impl<'l> DoubleEndedIterator for IxRange<'l> {
    fn next_back(&mut self) -> Option<Self::Item> {
        (**self).next_back().map(|i| unsafe { Ix::from_raw(i) })
    }
}

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

    #[test]
    fn it_works() {
        let n_ = 42;
        imprint(n_, |n| {
            let vec: Vec<usize> = (0 .. n_).collect();
            let slice = Sl::from_slice(&vec, n).unwrap();
            let mut a = BoxedSl::new(n, 0.0);
            let mut b = BoxedSl::new(n, 0.0);
            for i in IxRange::new_full(n) {
                let i_ = *i;
                a[i] = i_ as f64 * 0.5;
                b[i] = (n_ - i_) as f64;
            }
            for i in IxRange::new_full(n) {
                let i_ = *i;
                assert_eq!(slice[i], i_);
                assert_eq!(a[i], i_ as f64 * 0.5);
                assert_eq!(b[i], (n_ - i_) as f64);
            }
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! General — Library initialization and miscellaneous functions

use std::cell::Cell;
use std::ptr;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

use ffi;

thread_local! {
    static IS_MAIN_THREAD: Cell<bool> = Cell::new(false)
}

static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;

/// Asserts that this is the main thread and either `gdk::init` or `gtk::init` has been called.
macro_rules! assert_initialized_main_thread {
    () => (
        if !::rt::is_initialized_main_thread() {
            if ::rt::is_initialized() {
                panic!("GDK may only be used from the main thread.");
            }
            else {
                panic!("GDK has not been initialized. Call `gdk::init` or `gtk::init` first.");
            }
        }
    )
}

/// No-op.
macro_rules! skip_assert_initialized {
    () => ()
}

/// Asserts that neither `gdk::init` nor `gtk::init` has been called.
macro_rules! assert_not_initialized {
    () => (
        if ::rt::is_initialized() {
            panic!("This function has to be called before `gdk::init` or `gtk::init`.");
        }
    )
}

/// Returns `true` if GDK has been initialized.
#[inline]
pub fn is_initialized() -> bool {
    skip_assert_initialized!();
    INITIALIZED.load(Ordering::Acquire)
}

/// Returns `true` if GDK has been initialized and this is the main thread.
#[inline]
pub fn is_initialized_main_thread() -> bool {
    skip_assert_initialized!();
    IS_MAIN_THREAD.with(|c| c.get())
}

/// Informs this crate that GDK has been initialized and the current thread is the main one.
pub unsafe fn set_initialized() {
    skip_assert_initialized!();
    if is_initialized_main_thread() {
        return;
    }
    else if is_initialized() {
        panic!("Attempted to initialize GDK from two different threads.");
    }
    INITIALIZED.store(true, Ordering::Release);
    IS_MAIN_THREAD.with(|c| c.set(true));
}

pub fn init() {
    assert_not_initialized!();
    unsafe {
        ffi::gdk_init(ptr::null_mut(), ptr::null_mut());
        set_initialized();
    }
}
<commit_msg>Revert missed file for "Remove callback_guard"<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! General — Library initialization and miscellaneous functions

use std::cell::Cell;
use std::ptr;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

use ffi;

thread_local! {
    static IS_MAIN_THREAD: Cell<bool> = Cell::new(false)
}

static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;

/// Asserts that this is the main thread and either `gdk::init` or `gtk::init` has been called.
macro_rules! assert_initialized_main_thread {
    () => (
        if !::rt::is_initialized_main_thread() {
            if ::rt::is_initialized() {
                panic!("GDK may only be used from the main thread.");
            }
            else {
                panic!("GDK has not been initialized. Call `gdk::init` or `gtk::init` first.");
            }
        }
    )
}

/// No-op.
macro_rules! skip_assert_initialized {
    () => ()
}

/// Asserts that neither `gdk::init` nor `gtk::init` has been called.
macro_rules! assert_not_initialized {
    () => (
        if ::rt::is_initialized() {
            panic!("This function has to be called before `gdk::init` or `gtk::init`.");
        }
    )
}

macro_rules! callback_guard {
    () => (
        let _guard = ::glib::CallbackGuard::new();
        if cfg!(debug_assertions) {
            assert_initialized_main_thread!();
        }
    )
}

/// Returns `true` if GDK has been initialized.
#[inline]
pub fn is_initialized() -> bool {
    skip_assert_initialized!();
    INITIALIZED.load(Ordering::Acquire)
}

/// Returns `true` if GDK has been initialized and this is the main thread.
#[inline]
pub fn is_initialized_main_thread() -> bool {
    skip_assert_initialized!();
    IS_MAIN_THREAD.with(|c| c.get())
}

/// Informs this crate that GDK has been initialized and the current thread is the main one.
pub unsafe fn set_initialized() {
    skip_assert_initialized!();
    if is_initialized_main_thread() {
        return;
    }
    else if is_initialized() {
        panic!("Attempted to initialize GDK from two different threads.");
    }
    INITIALIZED.store(true, Ordering::Release);
    IS_MAIN_THREAD.with(|c| c.set(true));
}

pub fn init() {
    assert_not_initialized!();
    unsafe {
        ffi::gdk_init(ptr::null_mut(), ptr::null_mut());
        set_initialized();
    }
}
<|endoftext|>


<commit_before>pub fn reply(message: &str) -> &str {
    if is_silence(message) { "Fine. Be that way." }
    else if is_yelling(message) { "Woah, chill out!" }
    else if is_question(message) { "Sure." }
    else  { "Whatever." }
}

fn is_silence(message: &str) -> bool {
    message == ""
}

fn is_yelling(message: &str) -> bool {
    let upcase_message: &[Ascii] = message.to_ascii().to_upper();
    let ascii_message: &[Ascii] = message.to_ascii();
    upcase_message == ascii_message
}

fn is_question(message: &str) -> bool {
    message.ends_with("?")
}
<commit_msg>Improve implementation of is_yelling<commit_after>pub fn reply(message: &str) -> &str {
    if is_silence(message) { "Fine. Be that way." }
    else if is_yelling(message) { "Woah, chill out!" }
    else if is_question(message) { "Sure." }
    else  { "Whatever." }
}

fn is_silence(message: &str) -> bool {
    message == ""
}

fn is_yelling(message: &str) -> bool {
    message.iter().all(|char| !char.is_lowercase())
}

fn is_question(message: &str) -> bool {
    message.ends_with("?")
}
<|endoftext|>


<commit_before>use crate::client::{InnerClient, Responses};
use crate::codec::FrontendMessage;
use crate::connection::RequestMessages;
use crate::{query, slice_iter, Error, Statement};
use bytes::Bytes;
use futures::{ready, Stream};
use log::debug;
use pin_project_lite::pin_project;
use postgres_protocol::message::backend::Message;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::{Context, Poll};

pub async fn copy_out(client: &InnerClient, statement: Statement) -> Result<CopyOutStream, Error> {
    debug!("executing copy out statement {}", statement.name());

    let buf = query::encode(client, &statement, slice_iter(&[]))?;
    let responses = start(client, buf).await?;
    Ok(CopyOutStream {
        responses,
        _p: PhantomPinned,
    })
}

async fn start(client: &InnerClient, buf: Bytes) -> Result<Responses, Error> {
    let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;

    println!("a");
    match responses.next().await? {
        Message::BindComplete => {}
        _ => return Err(Error::unexpected_message()),
    }

    println!("b");
    match responses.next().await? {
        Message::CopyOutResponse(_) => {}
        _ => return Err(Error::unexpected_message()),
    }

    Ok(responses)
}

pin_project! {
    /// A stream of `COPY ... TO STDOUT` query data.
    pub struct CopyOutStream {
        responses: Responses,
        #[pin]
        _p: PhantomPinned,
    }
}

impl Stream for CopyOutStream {
    type Item = Result<Bytes, Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let this = self.project();

        println!("c");
        match ready!(this.responses.poll_next(cx)?) {
            Message::CopyData(body) => Poll::Ready(Some(Ok(body.into_bytes()))),
            Message::CopyDone => Poll::Ready(None),
            _ => Poll::Ready(Some(Err(Error::unexpected_message()))),
        }
    }
}
<commit_msg>Remove debugging printlns from copy out protocol<commit_after>use crate::client::{InnerClient, Responses};
use crate::codec::FrontendMessage;
use crate::connection::RequestMessages;
use crate::{query, slice_iter, Error, Statement};
use bytes::Bytes;
use futures::{ready, Stream};
use log::debug;
use pin_project_lite::pin_project;
use postgres_protocol::message::backend::Message;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::{Context, Poll};

pub async fn copy_out(client: &InnerClient, statement: Statement) -> Result<CopyOutStream, Error> {
    debug!("executing copy out statement {}", statement.name());

    let buf = query::encode(client, &statement, slice_iter(&[]))?;
    let responses = start(client, buf).await?;
    Ok(CopyOutStream {
        responses,
        _p: PhantomPinned,
    })
}

async fn start(client: &InnerClient, buf: Bytes) -> Result<Responses, Error> {
    let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;

    match responses.next().await? {
        Message::BindComplete => {}
        _ => return Err(Error::unexpected_message()),
    }

    match responses.next().await? {
        Message::CopyOutResponse(_) => {}
        _ => return Err(Error::unexpected_message()),
    }

    Ok(responses)
}

pin_project! {
    /// A stream of `COPY ... TO STDOUT` query data.
    pub struct CopyOutStream {
        responses: Responses,
        #[pin]
        _p: PhantomPinned,
    }
}

impl Stream for CopyOutStream {
    type Item = Result<Bytes, Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let this = self.project();

        match ready!(this.responses.poll_next(cx)?) {
            Message::CopyData(body) => Poll::Ready(Some(Ok(body.into_bytes()))),
            Message::CopyDone => Poll::Ready(None),
            _ => Poll::Ready(Some(Err(Error::unexpected_message()))),
        }
    }
}
<|endoftext|>


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

use crate::INTERNAL_METADATA_DIRECTIVE;
use common::{Diagnostic, DiagnosticsResult, NamedItem, WithLocation};
use graphql_ir::{
    Argument, ConstantArgument, ConstantValue, Directive, OperationDefinition, Program,
    Transformed, Transformer, ValidationMessage, Value,
};
use graphql_syntax::OperationKind;
use interner::{Intern, StringKey};
use lazy_static::lazy_static;

lazy_static! {
    pub static ref LIVE_QUERY_DIRECTIVE_NAME: StringKey = "live_query".intern();
    pub static ref LIVE_METADATA_KEY: StringKey = "live".intern();
    pub static ref PRELOADABLE_METADATA_KEY: StringKey = "relayPreloadable".intern();
    pub static ref POLLING_INTERVAL_ARG: StringKey = "polling_interval".intern();
    pub static ref CONFIG_ID_ARG: StringKey = "config_id".intern();
}

pub fn generate_live_query_metadata(program: &Program) -> DiagnosticsResult<Program> {
    let mut transformer = GenerateLiveQueryMetadata::new(program);
    let next_program = transformer
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transformer.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transformer.errors)
    }
}

struct GenerateLiveQueryMetadata<'s> {
    pub program: &'s Program,
    pub errors: Vec<Diagnostic>,
}

impl<'s> GenerateLiveQueryMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateLiveQueryMetadata {
            program,
            errors: vec![],
        }
    }
}

impl<'s> Transformer for GenerateLiveQueryMetadata<'s> {
    const NAME: &'static str = "GenerateLiveQueryMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        match operation.kind {
            OperationKind::Query => {
                let live_query_directive = operation.directives.named(*LIVE_QUERY_DIRECTIVE_NAME);

                if let Some(live_query_directive) = live_query_directive {
                    let polling_interval =
                        live_query_directive.arguments.named(*POLLING_INTERVAL_ARG);
                    let config_id = live_query_directive.arguments.named(*CONFIG_ID_ARG);

                    if polling_interval.is_none() && config_id.is_none() {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::LiveQueryTransformMissingConfig {
                                query_name: operation.name.item,
                            },
                            live_query_directive.name.location,
                        ));
                        return Transformed::Keep;
                    }

                    let mut next_directives = operation.directives.clone();

                    // I'm porting JS logic here. Not sure if the case where
                    // polling_interval and config_id both provided handeled correctly
                    if let Some(polling_interval) = polling_interval {
                        let poll_interval_value = match polling_interval.value.item {
                            Value::Constant(ConstantValue::Int(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidPollingInterval {
                                        query_name: operation.name.item,
                                    },
                                    polling_interval.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *POLLING_INTERVAL_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::Int(poll_interval_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    } else if let Some(config_id) = config_id {
                        let config_id_value = match config_id.value.item {
                            Value::Constant(ConstantValue::String(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidConfigId {
                                        query_name: operation.name.item,
                                    },
                                    config_id.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *CONFIG_ID_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::String(config_id_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    }

                    Transformed::Replace(OperationDefinition {
                        directives: next_directives,
                        ..operation.clone()
                    })
                } else {
                    Transformed::Keep
                }
            }
            _ => Transformed::Keep,
        }
    }
}
<commit_msg>fix typo in comment<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::INTERNAL_METADATA_DIRECTIVE;
use common::{Diagnostic, DiagnosticsResult, NamedItem, WithLocation};
use graphql_ir::{
    Argument, ConstantArgument, ConstantValue, Directive, OperationDefinition, Program,
    Transformed, Transformer, ValidationMessage, Value,
};
use graphql_syntax::OperationKind;
use interner::{Intern, StringKey};
use lazy_static::lazy_static;

lazy_static! {
    pub static ref LIVE_QUERY_DIRECTIVE_NAME: StringKey = "live_query".intern();
    pub static ref LIVE_METADATA_KEY: StringKey = "live".intern();
    pub static ref PRELOADABLE_METADATA_KEY: StringKey = "relayPreloadable".intern();
    pub static ref POLLING_INTERVAL_ARG: StringKey = "polling_interval".intern();
    pub static ref CONFIG_ID_ARG: StringKey = "config_id".intern();
}

pub fn generate_live_query_metadata(program: &Program) -> DiagnosticsResult<Program> {
    let mut transformer = GenerateLiveQueryMetadata::new(program);
    let next_program = transformer
        .transform_program(program)
        .replace_or_else(|| program.clone());

    if transformer.errors.is_empty() {
        Ok(next_program)
    } else {
        Err(transformer.errors)
    }
}

struct GenerateLiveQueryMetadata<'s> {
    pub program: &'s Program,
    pub errors: Vec<Diagnostic>,
}

impl<'s> GenerateLiveQueryMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateLiveQueryMetadata {
            program,
            errors: vec![],
        }
    }
}

impl<'s> Transformer for GenerateLiveQueryMetadata<'s> {
    const NAME: &'static str = "GenerateLiveQueryMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        match operation.kind {
            OperationKind::Query => {
                let live_query_directive = operation.directives.named(*LIVE_QUERY_DIRECTIVE_NAME);

                if let Some(live_query_directive) = live_query_directive {
                    let polling_interval =
                        live_query_directive.arguments.named(*POLLING_INTERVAL_ARG);
                    let config_id = live_query_directive.arguments.named(*CONFIG_ID_ARG);

                    if polling_interval.is_none() && config_id.is_none() {
                        self.errors.push(Diagnostic::error(
                            ValidationMessage::LiveQueryTransformMissingConfig {
                                query_name: operation.name.item,
                            },
                            live_query_directive.name.location,
                        ));
                        return Transformed::Keep;
                    }

                    let mut next_directives = operation.directives.clone();

                    // I'm porting JS logic here. Not sure if the case where
                    // polling_interval and config_id both provided handled correctly
                    if let Some(polling_interval) = polling_interval {
                        let poll_interval_value = match polling_interval.value.item {
                            Value::Constant(ConstantValue::Int(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidPollingInterval {
                                        query_name: operation.name.item,
                                    },
                                    polling_interval.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *POLLING_INTERVAL_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::Int(poll_interval_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    } else if let Some(config_id) = config_id {
                        let config_id_value = match config_id.value.item {
                            Value::Constant(ConstantValue::String(value)) => value,
                            _ => {
                                self.errors.push(Diagnostic::error(
                                    ValidationMessage::LiveQueryTransformInvalidConfigId {
                                        query_name: operation.name.item,
                                    },
                                    config_id.value.location,
                                ));
                                return Transformed::Keep;
                            }
                        };
                        next_directives.push(Directive {
                            name: WithLocation::new(
                                operation.name.location,
                                *INTERNAL_METADATA_DIRECTIVE,
                            ),
                            arguments: vec![Argument {
                                name: WithLocation::new(
                                    operation.name.location,
                                    *LIVE_METADATA_KEY,
                                ),
                                value: WithLocation::new(
                                    operation.name.location,
                                    Value::Constant(ConstantValue::Object(vec![
                                        ConstantArgument {
                                            name: WithLocation::new(
                                                operation.name.location,
                                                *CONFIG_ID_ARG,
                                            ),
                                            value: WithLocation::new(
                                                operation.name.location,
                                                ConstantValue::String(config_id_value),
                                            ),
                                        },
                                    ])),
                                ),
                            }],
                        });
                    }

                    Transformed::Replace(OperationDefinition {
                        directives: next_directives,
                        ..operation.clone()
                    })
                } else {
                    Transformed::Keep
                }
            }
            _ => Transformed::Keep,
        }
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

use ops::{self, CompileFilter};
use util::{self, CargoResult, process, ProcessError};
use core::Workspace;

pub fn run(ws: &Workspace,
           options: &ops::CompileOptions,
           args: &[String]) -> CargoResult<Option<ProcessError>> {
    let config = ws.config();
    let root = try!(ws.current());

    let mut bins = root.manifest().targets().iter().filter(|a| {
        !a.is_lib() && !a.is_custom_build() && match options.filter {
            CompileFilter::Everything => a.is_bin(),
            CompileFilter::Only { .. } => options.filter.matches(a),
        }
    });
    if bins.next().is_none() {
        match options.filter {
            CompileFilter::Everything => {
                bail!("a bin target must be available for `cargo run`")
            }
            CompileFilter::Only { .. } => {
                // this will be verified in cargo_compile
            }
        }
    }
    if bins.next().is_some() {
        match options.filter {
            CompileFilter::Everything => {
                bail!("`cargo run` requires that a project only have one \
                       executable; use the `--bin` option to specify which one \
                       to run")
            }
            CompileFilter::Only { .. } => {
                bail!("`cargo run` can run at most one executable, but \
                       multiple were specified")
            }
        }
    }

    let compile = try!(ops::compile(ws, options));
    let exe = &compile.binaries[0];
    let exe = match util::without_prefix(&exe, config.cwd()) {
        Some(path) if path.file_name() == Some(path.as_os_str())
                   => Path::new(".").join(path).to_path_buf(),
        Some(path) => path.to_path_buf(),
        None => exe.to_path_buf(),
    };
    let mut process = try!(compile.target_process(exe, &root))
                                  .into_process_builder();
    process.args(args).cwd(config.cwd());

    try!(config.shell().status("Running", process.to_string()));
    Ok(process.exec().err())
}
<commit_msg>Auto merge of #2942 - jseyfried:remove_unused_import, r=alexcrichton<commit_after>use std::path::Path;

use ops::{self, CompileFilter};
use util::{self, CargoResult, ProcessError};
use core::Workspace;

pub fn run(ws: &Workspace,
           options: &ops::CompileOptions,
           args: &[String]) -> CargoResult<Option<ProcessError>> {
    let config = ws.config();
    let root = try!(ws.current());

    let mut bins = root.manifest().targets().iter().filter(|a| {
        !a.is_lib() && !a.is_custom_build() && match options.filter {
            CompileFilter::Everything => a.is_bin(),
            CompileFilter::Only { .. } => options.filter.matches(a),
        }
    });
    if bins.next().is_none() {
        match options.filter {
            CompileFilter::Everything => {
                bail!("a bin target must be available for `cargo run`")
            }
            CompileFilter::Only { .. } => {
                // this will be verified in cargo_compile
            }
        }
    }
    if bins.next().is_some() {
        match options.filter {
            CompileFilter::Everything => {
                bail!("`cargo run` requires that a project only have one \
                       executable; use the `--bin` option to specify which one \
                       to run")
            }
            CompileFilter::Only { .. } => {
                bail!("`cargo run` can run at most one executable, but \
                       multiple were specified")
            }
        }
    }

    let compile = try!(ops::compile(ws, options));
    let exe = &compile.binaries[0];
    let exe = match util::without_prefix(&exe, config.cwd()) {
        Some(path) if path.file_name() == Some(path.as_os_str())
                   => Path::new(".").join(path).to_path_buf(),
        Some(path) => path.to_path_buf(),
        None => exe.to_path_buf(),
    };
    let mut process = try!(compile.target_process(exe, &root))
                                  .into_process_builder();
    process.args(args).cwd(config.cwd());

    try!(config.shell().status("Running", process.to_string()));
    Ok(process.exec().err())
}
<|endoftext|>


<commit_before>//! Tests and test utilities for completions.
//!
//! Most tests live in this module or its submodules. The tests in these submodules are "location"
//! oriented, that is they try to check completions for something like type position, param position
//! etc.
//! Tests that are more orientated towards specific completion types like visibility checks of path
//! completions or `check_edit` tests usually live in their respective completion modules instead.
//! This gives this test module and its submodules here the main purpose of giving the developer an
//! overview of whats being completed where, not how.

mod attribute;
mod expression;
mod flyimport;
mod fn_param;
mod item_list;
mod item;
mod pattern;
mod predicate;
mod proc_macros;
mod record;
mod special;
mod type_pos;
mod use_tree;
mod visibility;

use std::mem;

use hir::{db::DefDatabase, PrefixKind, Semantics};
use ide_db::{
    base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
    imports::insert_use::{ImportGranularity, InsertUseConfig},
    RootDatabase, SnippetCap,
};
use itertools::Itertools;
use stdx::{format_to, trim_indent};
use syntax::{AstNode, NodeOrToken, SyntaxElement};
use test_utils::assert_eq_text;

use crate::{
    resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem,
    CompletionItemKind,
};

/// Lots of basic item definitions
const BASE_ITEMS_FIXTURE: &str = r#"
enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
use self::Enum::TupleV;
mod module {}

trait Trait {}
static STATIC: Unit = Unit;
const CONST: Unit = Unit;
struct Record { field: u32 }
struct Tuple(u32);
struct Unit;
#[macro_export]
macro_rules! makro {}
#[rustc_builtin_macro]
pub macro Clone {}
fn function() {}
union Union { field: i32 }
"#;

pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
    enable_postfix_completions: true,
    enable_imports_on_the_fly: true,
    enable_self_on_the_fly: true,
    enable_private_editable: false,
    callable: Some(CallableSnippets::FillArguments),
    snippet_cap: SnippetCap::new(true),
    insert_use: InsertUseConfig {
        granularity: ImportGranularity::Crate,
        prefix_kind: PrefixKind::Plain,
        enforce_granularity: true,
        group: true,
        skip_glob_imports: true,
    },
    snippets: Vec::new(),
};

pub(crate) fn completion_list(ra_fixture: &str) -> String {
    completion_list_with_config(TEST_CONFIG, ra_fixture, true, None)
}

pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
    completion_list_with_config(TEST_CONFIG, ra_fixture, false, None)
}

pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String {
    let mut config = TEST_CONFIG.clone();
    config.enable_private_editable = true;
    completion_list_with_config(config, ra_fixture, false, None)
}

pub(crate) fn completion_list_with_trigger_character(
    ra_fixture: &str,
    trigger_character: Option<char>,
) -> String {
    completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character)
}

fn completion_list_with_config(
    config: CompletionConfig,
    ra_fixture: &str,
    include_keywords: bool,
    trigger_character: Option<char>,
) -> String {
    // filter out all but one builtintype completion for smaller test outputs
    let items = get_all_items(config, ra_fixture, trigger_character);
    let mut bt_seen = false;
    let items = items
        .into_iter()
        .filter(|it| {
            it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
        })
        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
        .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
        .collect();
    render_completion_list(items)
}

/// Creates analysis from a multi-file fixture, returns positions marked with $0.
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
    let change_fixture = ChangeFixture::parse(ra_fixture);
    let mut database = RootDatabase::default();
    database.set_enable_proc_attr_macros(true);
    database.apply_change(change_fixture.change);
    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
    let offset = range_or_offset.expect_offset();
    (database, FilePosition { file_id, offset })
}

pub(crate) fn do_completion(code: &str, kind: CompletionItemKind) -> Vec<CompletionItem> {
    do_completion_with_config(TEST_CONFIG, code, kind)
}

pub(crate) fn do_completion_with_config(
    config: CompletionConfig,
    code: &str,
    kind: CompletionItemKind,
) -> Vec<CompletionItem> {
    get_all_items(config, code, None)
        .into_iter()
        .filter(|c| c.kind() == kind)
        .sorted_by(|l, r| l.label().cmp(r.label()))
        .collect()
}

fn render_completion_list(completions: Vec<CompletionItem>) -> String {
    fn monospace_width(s: &str) -> usize {
        s.chars().count()
    }
    let label_width =
        completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(22);
    completions
        .into_iter()
        .map(|it| {
            let tag = it.kind().tag();
            let var_name = format!("{} {}", tag, it.label());
            let mut buf = var_name;
            if let Some(detail) = it.detail() {
                let width = label_width.saturating_sub(monospace_width(it.label()));
                format_to!(buf, "{:width$} {}", "", detail, width = width);
            }
            if it.deprecated() {
                format_to!(buf, " DEPRECATED");
            }
            format_to!(buf, "\n");
            buf
        })
        .collect()
}

#[track_caller]
pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
    check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after)
}

#[track_caller]
pub(crate) fn check_edit_with_config(
    config: CompletionConfig,
    what: &str,
    ra_fixture_before: &str,
    ra_fixture_after: &str,
) {
    let ra_fixture_after = trim_indent(ra_fixture_after);
    let (db, position) = position(ra_fixture_before);
    let completions: Vec<CompletionItem> =
        crate::completions(&db, &config, position, None).unwrap().into();
    let (completion,) = completions
        .iter()
        .filter(|it| it.lookup() == what)
        .collect_tuple()
        .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
    let mut actual = db.file_text(position.file_id).to_string();

    let mut combined_edit = completion.text_edit().to_owned();

    resolve_completion_edits(
        &db,
        &config,
        position,
        completion.imports_to_add().iter().filter_map(|import_edit| {
            let import_path = &import_edit.import_path;
            let import_name = import_path.segments().last()?;
            Some((import_path.to_string(), import_name.to_string()))
        }),
    )
    .into_iter()
    .flatten()
    .for_each(|text_edit| {
        combined_edit.union(text_edit).expect(
            "Failed to apply completion resolve changes: change ranges overlap, but should not",
        )
    });

    combined_edit.apply(&mut actual);
    assert_eq_text!(&ra_fixture_after, &actual)
}

pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxElement) -> bool) {
    let (db, pos) = position(code);

    let sema = Semantics::new(&db);
    let original_file = sema.parse(pos.file_id);
    let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
    assert!(check(NodeOrToken::Token(token)));
}

pub(crate) fn get_all_items(
    config: CompletionConfig,
    code: &str,
    trigger_character: Option<char>,
) -> Vec<CompletionItem> {
    let (db, position) = position(code);
    let res = crate::completions(&db, &config, position, trigger_character)
        .map_or_else(Vec::default, Into::into);
    // validate
    res.iter().for_each(|it| {
        let sr = it.source_range();
        assert!(
            sr.contains_inclusive(position.offset),
            "source range {sr:?} does not contain the offset {:?} of the completion request: {it:?}",
            position.offset
        );
    });
    res
}

#[test]
fn test_no_completions_required() {
    assert_eq!(completion_list(r#"fn foo() { for i i$0 }"#), String::new());
}

#[test]
fn regression_10042() {
    completion_list(
        r#"
macro_rules! preset {
    ($($x:ident)&&*) => {
        {
            let mut v = Vec::new();
            $(
                v.push($x.into());
            )*
            v
        }
    };
}

fn foo() {
    preset!(foo$0);
}
"#,
    );
}

#[test]
fn no_completions_in_comments() {
    assert_eq!(
        completion_list(
            r#"
fn test() {
let x = 2; // A comment$0
}
"#,
        ),
        String::new(),
    );
    assert_eq!(
        completion_list(
            r#"
/*
Some multi-line comment$0
*/
"#,
        ),
        String::new(),
    );
    assert_eq!(
        completion_list(
            r#"
/// Some doc comment
/// let test$0 = 1
"#,
        ),
        String::new(),
    );
}
<commit_msg>Auto merge of #12904 - lnicola:completion-builtin-filter, r=lnicola<commit_after>//! Tests and test utilities for completions.
//!
//! Most tests live in this module or its submodules. The tests in these submodules are "location"
//! oriented, that is they try to check completions for something like type position, param position
//! etc.
//! Tests that are more orientated towards specific completion types like visibility checks of path
//! completions or `check_edit` tests usually live in their respective completion modules instead.
//! This gives this test module and its submodules here the main purpose of giving the developer an
//! overview of whats being completed where, not how.

mod attribute;
mod expression;
mod flyimport;
mod fn_param;
mod item_list;
mod item;
mod pattern;
mod predicate;
mod proc_macros;
mod record;
mod special;
mod type_pos;
mod use_tree;
mod visibility;

use hir::{db::DefDatabase, PrefixKind, Semantics};
use ide_db::{
    base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
    imports::insert_use::{ImportGranularity, InsertUseConfig},
    RootDatabase, SnippetCap,
};
use itertools::Itertools;
use stdx::{format_to, trim_indent};
use syntax::{AstNode, NodeOrToken, SyntaxElement};
use test_utils::assert_eq_text;

use crate::{
    resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem,
    CompletionItemKind,
};

/// Lots of basic item definitions
const BASE_ITEMS_FIXTURE: &str = r#"
enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
use self::Enum::TupleV;
mod module {}

trait Trait {}
static STATIC: Unit = Unit;
const CONST: Unit = Unit;
struct Record { field: u32 }
struct Tuple(u32);
struct Unit;
#[macro_export]
macro_rules! makro {}
#[rustc_builtin_macro]
pub macro Clone {}
fn function() {}
union Union { field: i32 }
"#;

pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
    enable_postfix_completions: true,
    enable_imports_on_the_fly: true,
    enable_self_on_the_fly: true,
    enable_private_editable: false,
    callable: Some(CallableSnippets::FillArguments),
    snippet_cap: SnippetCap::new(true),
    insert_use: InsertUseConfig {
        granularity: ImportGranularity::Crate,
        prefix_kind: PrefixKind::Plain,
        enforce_granularity: true,
        group: true,
        skip_glob_imports: true,
    },
    snippets: Vec::new(),
};

pub(crate) fn completion_list(ra_fixture: &str) -> String {
    completion_list_with_config(TEST_CONFIG, ra_fixture, true, None)
}

pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
    completion_list_with_config(TEST_CONFIG, ra_fixture, false, None)
}

pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String {
    let mut config = TEST_CONFIG.clone();
    config.enable_private_editable = true;
    completion_list_with_config(config, ra_fixture, false, None)
}

pub(crate) fn completion_list_with_trigger_character(
    ra_fixture: &str,
    trigger_character: Option<char>,
) -> String {
    completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character)
}

fn completion_list_with_config(
    config: CompletionConfig,
    ra_fixture: &str,
    include_keywords: bool,
    trigger_character: Option<char>,
) -> String {
    // filter out all but one builtintype completion for smaller test outputs
    let items = get_all_items(config, ra_fixture, trigger_character);
    let items = items
        .into_iter()
        .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
        .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
        .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
        .collect();
    render_completion_list(items)
}

/// Creates analysis from a multi-file fixture, returns positions marked with $0.
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
    let change_fixture = ChangeFixture::parse(ra_fixture);
    let mut database = RootDatabase::default();
    database.set_enable_proc_attr_macros(true);
    database.apply_change(change_fixture.change);
    let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
    let offset = range_or_offset.expect_offset();
    (database, FilePosition { file_id, offset })
}

pub(crate) fn do_completion(code: &str, kind: CompletionItemKind) -> Vec<CompletionItem> {
    do_completion_with_config(TEST_CONFIG, code, kind)
}

pub(crate) fn do_completion_with_config(
    config: CompletionConfig,
    code: &str,
    kind: CompletionItemKind,
) -> Vec<CompletionItem> {
    get_all_items(config, code, None)
        .into_iter()
        .filter(|c| c.kind() == kind)
        .sorted_by(|l, r| l.label().cmp(r.label()))
        .collect()
}

fn render_completion_list(completions: Vec<CompletionItem>) -> String {
    fn monospace_width(s: &str) -> usize {
        s.chars().count()
    }
    let label_width =
        completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(22);
    completions
        .into_iter()
        .map(|it| {
            let tag = it.kind().tag();
            let var_name = format!("{} {}", tag, it.label());
            let mut buf = var_name;
            if let Some(detail) = it.detail() {
                let width = label_width.saturating_sub(monospace_width(it.label()));
                format_to!(buf, "{:width$} {}", "", detail, width = width);
            }
            if it.deprecated() {
                format_to!(buf, " DEPRECATED");
            }
            format_to!(buf, "\n");
            buf
        })
        .collect()
}

#[track_caller]
pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
    check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after)
}

#[track_caller]
pub(crate) fn check_edit_with_config(
    config: CompletionConfig,
    what: &str,
    ra_fixture_before: &str,
    ra_fixture_after: &str,
) {
    let ra_fixture_after = trim_indent(ra_fixture_after);
    let (db, position) = position(ra_fixture_before);
    let completions: Vec<CompletionItem> =
        crate::completions(&db, &config, position, None).unwrap().into();
    let (completion,) = completions
        .iter()
        .filter(|it| it.lookup() == what)
        .collect_tuple()
        .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
    let mut actual = db.file_text(position.file_id).to_string();

    let mut combined_edit = completion.text_edit().to_owned();

    resolve_completion_edits(
        &db,
        &config,
        position,
        completion.imports_to_add().iter().filter_map(|import_edit| {
            let import_path = &import_edit.import_path;
            let import_name = import_path.segments().last()?;
            Some((import_path.to_string(), import_name.to_string()))
        }),
    )
    .into_iter()
    .flatten()
    .for_each(|text_edit| {
        combined_edit.union(text_edit).expect(
            "Failed to apply completion resolve changes: change ranges overlap, but should not",
        )
    });

    combined_edit.apply(&mut actual);
    assert_eq_text!(&ra_fixture_after, &actual)
}

pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxElement) -> bool) {
    let (db, pos) = position(code);

    let sema = Semantics::new(&db);
    let original_file = sema.parse(pos.file_id);
    let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
    assert!(check(NodeOrToken::Token(token)));
}

pub(crate) fn get_all_items(
    config: CompletionConfig,
    code: &str,
    trigger_character: Option<char>,
) -> Vec<CompletionItem> {
    let (db, position) = position(code);
    let res = crate::completions(&db, &config, position, trigger_character)
        .map_or_else(Vec::default, Into::into);
    // validate
    res.iter().for_each(|it| {
        let sr = it.source_range();
        assert!(
            sr.contains_inclusive(position.offset),
            "source range {sr:?} does not contain the offset {:?} of the completion request: {it:?}",
            position.offset
        );
    });
    res
}

#[test]
fn test_no_completions_required() {
    assert_eq!(completion_list(r#"fn foo() { for i i$0 }"#), String::new());
}

#[test]
fn regression_10042() {
    completion_list(
        r#"
macro_rules! preset {
    ($($x:ident)&&*) => {
        {
            let mut v = Vec::new();
            $(
                v.push($x.into());
            )*
            v
        }
    };
}

fn foo() {
    preset!(foo$0);
}
"#,
    );
}

#[test]
fn no_completions_in_comments() {
    assert_eq!(
        completion_list(
            r#"
fn test() {
let x = 2; // A comment$0
}
"#,
        ),
        String::new(),
    );
    assert_eq!(
        completion_list(
            r#"
/*
Some multi-line comment$0
*/
"#,
        ),
        String::new(),
    );
    assert_eq!(
        completion_list(
            r#"
/// Some doc comment
/// let test$0 = 1
"#,
        ),
        String::new(),
    );
}
<|endoftext|>


<commit_before>import std::run;
import std::run::spawn_process;
import std::io;
import std::os;
import io::writer_util;
import ctypes::{pid_t, fd_t};

export run;

#[cfg(target_os = "win32")]
fn target_env(lib_path: str, prog: str) -> option<[(str,str)]> {

    let env = std::generic_os::env();

    env = vec::map(env) {|pair|
        let (k,v) = pair;
        if k == "PATH" { ("PATH", v + ";" + lib_path) }
        else { (k,v) }
    };
    if str::ends_with(prog, "rustc.exe") {
        env += [("RUST_THREADS", "1")]
    }
    ret some(env);
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn target_env(_lib_path: str, _prog: str) -> option<[(str,str)]> {
    none
}

fn run(lib_path: str, prog: str, args: [str],
       input: option<str>) -> {status: int, out: str, err: str} {

    let pipe_in = os::pipe();
    let pipe_out = os::pipe();
    let pipe_err = os::pipe();
    let pid = spawn_process(prog, args, target_env(lib_path, prog), none,
                            pipe_in.in, pipe_out.out, pipe_err.out);

    os::close(pipe_in.in);
    os::close(pipe_out.out);
    os::close(pipe_err.out);
    if pid == -1i32 {
        os::close(pipe_in.out);
        os::close(pipe_out.in);
        os::close(pipe_err.in);
        fail;
    }

    writeclose(pipe_in.out, input);
    let output = readclose(pipe_out.in);
    let errput = readclose(pipe_err.in);
    let status = run::waitpid(pid);
    ret {status: status, out: output, err: errput};
}

fn writeclose(fd: fd_t, s: option<str>) {
    if option::is_some(s) {
        let writer = io::fd_writer(fd, false);
        writer.write_str(option::get(s));
    }

    os::close(fd);
}

fn readclose(fd: fd_t) -> str {
    // Copied from run::program_output
    let file = os::fd_FILE(fd);
    let reader = io::FILE_reader(file, false);
    let buf = "";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    ret buf;
}
<commit_msg>read stderr before stdout<commit_after>import std::run;
import std::run::spawn_process;
import std::io;
import std::os;
import io::writer_util;
import ctypes::{pid_t, fd_t};

export run;

#[cfg(target_os = "win32")]
fn target_env(lib_path: str, prog: str) -> option<[(str,str)]> {

    let env = std::generic_os::env();

    env = vec::map(env) {|pair|
        let (k,v) = pair;
        if k == "PATH" { ("PATH", v + ";" + lib_path) }
        else { (k,v) }
    };
    if str::ends_with(prog, "rustc.exe") {
        env += [("RUST_THREADS", "1")]
    }
    ret some(env);
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn target_env(_lib_path: str, _prog: str) -> option<[(str,str)]> {
    none
}

fn run(lib_path: str, prog: str, args: [str],
       input: option<str>) -> {status: int, out: str, err: str} {

    let pipe_in = os::pipe();
    let pipe_out = os::pipe();
    let pipe_err = os::pipe();
    let pid = spawn_process(prog, args, target_env(lib_path, prog), none,
                            pipe_in.in, pipe_out.out, pipe_err.out);

    os::close(pipe_in.in);
    os::close(pipe_out.out);
    os::close(pipe_err.out);
    if pid == -1i32 {
        os::close(pipe_in.out);
        os::close(pipe_out.in);
        os::close(pipe_err.in);
        fail;
    }

    writeclose(pipe_in.out, input);
    let errput = readclose(pipe_err.in);
    let output = readclose(pipe_out.in);
    let status = run::waitpid(pid);
    ret {status: status, out: output, err: errput};
}

fn writeclose(fd: fd_t, s: option<str>) {
    if option::is_some(s) {
        let writer = io::fd_writer(fd, false);
        writer.write_str(option::get(s));
    }

    os::close(fd);
}

fn readclose(fd: fd_t) -> str {
    // Copied from run::program_output
    let file = os::fd_FILE(fd);
    let reader = io::FILE_reader(file, false);
    let buf = "";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    ret buf;
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::marker::PhantomData;
use std::rc::Rc;

use anyhow::{anyhow, Result};

use crate::bindings;
use crate::buffer::Buffer;
use crate::context::Context;
use crate::status::Status;
use crate::surface::Surface;

// Use the sealed trait pattern to make sure that new states are not created in
// caller code. More information about the sealed trait pattern can be found at
// <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed>
mod private {
    pub trait Sealed {}
}

/// A `Picture` will only have valid YUV data after a sequence of operations are
/// performed in a particular order. This order correspond to the following
/// VA-API calls: vaBeginPicture, vaRenderPicture, vaEndPicture and
/// vaSyncSurface. This trait enforces this ordering by implementing the
/// Typestate pattern to constrain what operations are available in what
/// particular states.
///
/// The states for the state machine are:
/// PictureNew -> PictureBegin
/// PictureBegin -> PictureRender
/// PictureRender ->PictureEnd
/// PictureEnd -> PictureSync
///
/// Where the surface can be reclaimed in both PictureNew and PictureSync, as
/// either no operation took place (as in PictureNew), or it is guaranteed that
/// the operation has already completed (as in PictureSync)
///
/// More information about the Typestate pattern can be found
/// at <http://cliffle.com/blog/rust-typestate/>
pub trait PictureState: private::Sealed {}

/// Represents a `Picture` that has just been created.
pub enum PictureNew {}
impl PictureState for PictureNew {}
impl private::Sealed for PictureNew {}

/// Represents a `Picture` after `vaBeginPicture` has been called.
pub enum PictureBegin {}
impl PictureState for PictureBegin {}
impl private::Sealed for PictureBegin {}

/// Represents a `Picture` after `vaRenderPicture` has been called.
pub enum PictureRender {}
impl PictureState for PictureRender {}
impl private::Sealed for PictureRender {}

/// Represents a `Picture` after `vaEndPicture` has been called.
pub enum PictureEnd {}
impl PictureState for PictureEnd {}
impl private::Sealed for PictureEnd {}

/// Represents a `Picture` after `vaSyncSurface` has been called on the
/// underlying surface.
pub enum PictureSync {}
impl PictureState for PictureSync {}
impl private::Sealed for PictureSync {}

/// Represents a state where one can reclaim the underlying `Surface` for this
/// `Picture`. This is true when either no decoding has been initiated or,
/// alternatively, when the decoding operation has completed for the underlying
/// `vaSurface`
pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
impl PictureReclaimableSurface for PictureNew {}
impl PictureReclaimableSurface for PictureSync {}

pub(crate) struct PictureInner {
    /// Timestamp of the picture
    timestamp: u64,
    /// A context associated with this picture
    context: Rc<Context>,
    /// Contains the buffers used to decode the data
    buffers: Vec<Buffer>,
    /// Contains the actual decoded data. Note that the surface may be shared in
    /// interlaced decoding.
    surface: Rc<RefCell<Surface>>,
}

impl PictureInner {
    /// Returns a reference to the Context used by the Picture
    pub(crate) fn context(&self) -> Rc<Context> {
        Rc::clone(&self.context)
    }
}

/// An abstraction over VABuffers and a VASurface suitable for decoding with
/// vaBeginPicture, vaRenderPicture, vaEndPicture "surface" will have valid raw
/// picture data after "begin", "render", "end" and "sync" are called, in this
/// order.
pub struct Picture<S: PictureState> {
    inner: Box<PictureInner>,
    phantom: std::marker::PhantomData<S>,
}

impl Picture<PictureNew> {
    /// Creates a new Picture with a given `frame_number` to identify it.
    /// `surface` is the underlying surface that libva will render to.
    pub fn new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self {
        Self {
            inner: Box::new(PictureInner {
                timestamp,
                context,
                buffers: Default::default(),
                surface: Rc::new(RefCell::new(surface)),
            }),

            phantom: PhantomData,
        }
    }

    /// Creates a new Picture with a given `frame_number` to identify it,
    /// reusing the Surface from `picture`. This is useful for interlaced
    /// decoding as one can render both fields to the same underlying surface.
    pub fn new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>(
        timestamp: u64,
        picture: &Picture<S>,
    ) -> Picture<T> {
        let context = Rc::clone(&picture.inner.context);
        Picture {
            inner: Box::new(PictureInner {
                timestamp,
                context,
                buffers: Default::default(),
                surface: Rc::clone(&picture.inner.surface),
            }),

            phantom: PhantomData,
        }
    }

    /// Add buffers to a picture
    pub fn add_buffer(&mut self, buffer: Buffer) {
        self.inner.buffers.push(buffer);
    }

    /// A wrapper around vaBeginPicture
    pub fn begin(self) -> Result<Picture<PictureBegin>> {
        // Safe because `self.inner.context` represents a valid VAContext and
        // `self.inner.surface` represents a valid VASurface.
        Status(unsafe {
            bindings::vaBeginPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
                self.inner.surface.borrow().id(),
            )
        })
        .check()?;

        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureBegin> {
    /// A wrapper around vaRenderPicture
    pub fn render(self) -> Result<Picture<PictureRender>> {
        // Safe because `self.inner.context` represents a valid VAContext and
        // `self.inner.surface` represents a valid VASurface. `buffers` point to
        // a Rust struct and the vector length is passed to the C function, so
        // it is impossible to write past the end of the vector's storage by
        // mistake.
        Status(unsafe {
            bindings::vaRenderPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
                Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
                self.inner.buffers.len() as i32,
            )
        })
        .check()?;

        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureRender> {
    /// A wrapper around vaEndPicture
    pub fn end(self) -> Result<Picture<PictureEnd>> {
        // Safe because `self.inner.context` represents a valid VAContext.
        Status(unsafe {
            bindings::vaEndPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
            )
        })
        .check()?;
        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureEnd> {
    /// Syncs the picture, ensuring that any pending decode operations are
    /// complete when this call returns
    pub fn sync(self) -> Result<Picture<PictureSync>> {
        self.inner.surface.borrow().sync()?;

        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureSync> {
    /// Returns a reference to the underlying `Surface` for this
    /// `Picture`
    pub fn surface(&self) -> Ref<Surface> {
        self.inner.surface.borrow()
    }

    /// Returns a mutable reference to the underlying `Surface` for this
    /// `Picture`
    pub fn surface_mut(&mut self) -> RefMut<Surface> {
        self.inner.surface.borrow_mut()
    }
}

impl<S: PictureState> Picture<S> {
    /// Get the timestamp for this picture.
    pub fn timestamp(&self) -> u64 {
        self.inner.timestamp
    }

    /// Returns a reference to the `inner` struct
    pub(crate) fn inner(&self) -> &PictureInner {
        self.inner.as_ref()
    }
}

impl<S: PictureReclaimableSurface> Picture<S> {
    /// Reclaim ownership of the Surface, consuming the picture in the process.
    /// Useful if the Surface is part of a pool.
    pub fn take_surface(self) -> Result<Surface> {
        match Rc::try_unwrap(self.inner.surface) {
            Ok(surface) => Ok(surface.into_inner()),
            Err(_) => Err(anyhow!("Surface still in use")),
        }
    }
}
<commit_msg>media: libva: allow retrieving a Surface borrow in ReclaimableSurface<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
use std::marker::PhantomData;
use std::rc::Rc;

use anyhow::{anyhow, Result};

use crate::bindings;
use crate::buffer::Buffer;
use crate::context::Context;
use crate::status::Status;
use crate::surface::Surface;

// Use the sealed trait pattern to make sure that new states are not created in
// caller code. More information about the sealed trait pattern can be found at
// <https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed>
mod private {
    pub trait Sealed {}
}

/// A `Picture` will only have valid YUV data after a sequence of operations are
/// performed in a particular order. This order correspond to the following
/// VA-API calls: vaBeginPicture, vaRenderPicture, vaEndPicture and
/// vaSyncSurface. This trait enforces this ordering by implementing the
/// Typestate pattern to constrain what operations are available in what
/// particular states.
///
/// The states for the state machine are:
/// PictureNew -> PictureBegin
/// PictureBegin -> PictureRender
/// PictureRender ->PictureEnd
/// PictureEnd -> PictureSync
///
/// Where the surface can be reclaimed in both PictureNew and PictureSync, as
/// either no operation took place (as in PictureNew), or it is guaranteed that
/// the operation has already completed (as in PictureSync)
///
/// More information about the Typestate pattern can be found
/// at <http://cliffle.com/blog/rust-typestate/>
pub trait PictureState: private::Sealed {}

/// Represents a `Picture` that has just been created.
pub enum PictureNew {}
impl PictureState for PictureNew {}
impl private::Sealed for PictureNew {}

/// Represents a `Picture` after `vaBeginPicture` has been called.
pub enum PictureBegin {}
impl PictureState for PictureBegin {}
impl private::Sealed for PictureBegin {}

/// Represents a `Picture` after `vaRenderPicture` has been called.
pub enum PictureRender {}
impl PictureState for PictureRender {}
impl private::Sealed for PictureRender {}

/// Represents a `Picture` after `vaEndPicture` has been called.
pub enum PictureEnd {}
impl PictureState for PictureEnd {}
impl private::Sealed for PictureEnd {}

/// Represents a `Picture` after `vaSyncSurface` has been called on the
/// underlying surface.
pub enum PictureSync {}
impl PictureState for PictureSync {}
impl private::Sealed for PictureSync {}

/// Represents a state where one can reclaim the underlying `Surface` for this
/// `Picture`. This is true when either no decoding has been initiated or,
/// alternatively, when the decoding operation has completed for the underlying
/// `vaSurface`
pub trait PictureReclaimableSurface: PictureState + private::Sealed {}
impl PictureReclaimableSurface for PictureNew {}
impl PictureReclaimableSurface for PictureSync {}

pub(crate) struct PictureInner {
    /// Timestamp of the picture
    timestamp: u64,
    /// A context associated with this picture
    context: Rc<Context>,
    /// Contains the buffers used to decode the data
    buffers: Vec<Buffer>,
    /// Contains the actual decoded data. Note that the surface may be shared in
    /// interlaced decoding.
    surface: Rc<RefCell<Surface>>,
}

impl PictureInner {
    /// Returns a reference to the Context used by the Picture
    pub(crate) fn context(&self) -> Rc<Context> {
        Rc::clone(&self.context)
    }
}

/// An abstraction over VABuffers and a VASurface suitable for decoding with
/// vaBeginPicture, vaRenderPicture, vaEndPicture "surface" will have valid raw
/// picture data after "begin", "render", "end" and "sync" are called, in this
/// order.
pub struct Picture<S: PictureState> {
    inner: Box<PictureInner>,
    phantom: std::marker::PhantomData<S>,
}

impl Picture<PictureNew> {
    /// Creates a new Picture with a given `frame_number` to identify it.
    /// `surface` is the underlying surface that libva will render to.
    pub fn new(timestamp: u64, context: Rc<Context>, surface: Surface) -> Self {
        Self {
            inner: Box::new(PictureInner {
                timestamp,
                context,
                buffers: Default::default(),
                surface: Rc::new(RefCell::new(surface)),
            }),

            phantom: PhantomData,
        }
    }

    /// Creates a new Picture with a given `frame_number` to identify it,
    /// reusing the Surface from `picture`. This is useful for interlaced
    /// decoding as one can render both fields to the same underlying surface.
    pub fn new_from_same_surface<T: PictureReclaimableSurface, S: PictureReclaimableSurface>(
        timestamp: u64,
        picture: &Picture<S>,
    ) -> Picture<T> {
        let context = Rc::clone(&picture.inner.context);
        Picture {
            inner: Box::new(PictureInner {
                timestamp,
                context,
                buffers: Default::default(),
                surface: Rc::clone(&picture.inner.surface),
            }),

            phantom: PhantomData,
        }
    }

    /// Add buffers to a picture
    pub fn add_buffer(&mut self, buffer: Buffer) {
        self.inner.buffers.push(buffer);
    }

    /// A wrapper around vaBeginPicture
    pub fn begin(self) -> Result<Picture<PictureBegin>> {
        // Safe because `self.inner.context` represents a valid VAContext and
        // `self.inner.surface` represents a valid VASurface.
        Status(unsafe {
            bindings::vaBeginPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
                self.inner.surface.borrow().id(),
            )
        })
        .check()?;

        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureBegin> {
    /// A wrapper around vaRenderPicture
    pub fn render(self) -> Result<Picture<PictureRender>> {
        // Safe because `self.inner.context` represents a valid VAContext and
        // `self.inner.surface` represents a valid VASurface. `buffers` point to
        // a Rust struct and the vector length is passed to the C function, so
        // it is impossible to write past the end of the vector's storage by
        // mistake.
        Status(unsafe {
            bindings::vaRenderPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
                Buffer::as_id_vec(&self.inner.buffers).as_mut_ptr(),
                self.inner.buffers.len() as i32,
            )
        })
        .check()?;

        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureRender> {
    /// A wrapper around vaEndPicture
    pub fn end(self) -> Result<Picture<PictureEnd>> {
        // Safe because `self.inner.context` represents a valid VAContext.
        Status(unsafe {
            bindings::vaEndPicture(
                self.inner.context.display().handle(),
                self.inner.context.id(),
            )
        })
        .check()?;
        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl Picture<PictureEnd> {
    /// Syncs the picture, ensuring that any pending decode operations are
    /// complete when this call returns
    pub fn sync(self) -> Result<Picture<PictureSync>> {
        self.inner.surface.borrow().sync()?;

        Ok(Picture {
            inner: self.inner,
            phantom: PhantomData,
        })
    }
}

impl<S: PictureState> Picture<S> {
    /// Get the timestamp for this picture.
    pub fn timestamp(&self) -> u64 {
        self.inner.timestamp
    }

    /// Returns a reference to the `inner` struct
    pub(crate) fn inner(&self) -> &PictureInner {
        self.inner.as_ref()
    }
}

impl<S: PictureReclaimableSurface> Picture<S> {
    /// Reclaim ownership of the Surface, consuming the picture in the process.
    /// Useful if the Surface is part of a pool.
    pub fn take_surface(self) -> Result<Surface> {
        match Rc::try_unwrap(self.inner.surface) {
            Ok(surface) => Ok(surface.into_inner()),
            Err(_) => Err(anyhow!("Surface still in use")),
        }
    }

    /// Returns a reference to the underlying `Surface` for this
    /// `Picture`
    pub fn surface(&self) -> Ref<Surface> {
        self.inner.surface.borrow()
    }

    /// Returns a mutable reference to the underlying `Surface` for this
    /// `Picture`
    pub fn surface_mut(&mut self) -> RefMut<Surface> {
        self.inner.surface.borrow_mut()
    }
}
<|endoftext|>