<commit_before>// Copyright 2016 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A module for representing a set of breaks, typically used for
//! storing the result of line breaking.

use interval::Interval;
use std::cmp::min;
use std::mem;
use tree::{Leaf, Metric, Node, NodeInfo, TreeBuilder};

// Breaks represents a set of indexes. A motivating use is storing line breaks.
pub type Breaks = Node<BreaksInfo>;

// Here the base units are arbitrary, but most commonly match the base units
// of the rope storing the underlying string.

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct BreaksLeaf {
    len: usize,       // measured in base units
    data: Vec<usize>, // each is a delta relative to start of leaf; sorted
}

#[derive(Clone)]
pub struct BreaksInfo(usize); // number of breaks

impl Leaf for BreaksLeaf {
    fn len(&self) -> usize {
        self.len
    }

    fn is_ok_child(&self) -> bool {
        self.data.len() >= 32
    }

    fn push_maybe_split(&mut self, other: &BreaksLeaf, iv: Interval) -> Option<BreaksLeaf> {
        //eprintln!("push_maybe_split {:?} {:?} {}", self, other, iv);
        let (start, end) = iv.start_end();
        for &v in &other.data {
            if start < v && v <= end {
                self.data.push(v - start + self.len);
            }
        }
        // the min with other.len() shouldn't be needed
        self.len += min(end, other.len()) - start;

        if self.data.len() <= 64 {
            None
        } else {
            let splitpoint = self.data.len() / 2; // number of breaks
            let splitpoint_units = self.data[splitpoint - 1];
            // TODO: use Vec::split_off(), it's nicer
            let mut new = Vec::with_capacity(self.data.len() - splitpoint);
            for i in splitpoint..self.data.len() {
                new.push(self.data[i] - splitpoint_units);
            }
            let new_len = self.len - splitpoint_units;
            self.len = splitpoint_units;
            self.data.truncate(splitpoint);
            Some(BreaksLeaf { len: new_len, data: new })
        }
    }
}

impl NodeInfo for BreaksInfo {
    type L = BreaksLeaf;

    fn accumulate(&mut self, other: &Self) {
        self.0 += other.0;
    }

    fn compute_info(l: &BreaksLeaf) -> BreaksInfo {
        BreaksInfo(l.data.len())
    }
}

#[derive(Copy, Clone)]
pub struct BreaksMetric(());

impl Metric<BreaksInfo> for BreaksMetric {
    fn measure(info: &BreaksInfo, _: usize) -> usize {
        info.0
    }

    fn to_base_units(l: &BreaksLeaf, in_measured_units: usize) -> usize {
        if in_measured_units > l.data.len() {
            l.len + 1
        } else if in_measured_units == 0 {
            0
        } else {
            l.data[in_measured_units - 1]
        }
    }

    fn from_base_units(l: &BreaksLeaf, in_base_units: usize) -> usize {
        // TODO: binary search, data is sorted
        for i in 0..l.data.len() {
            if in_base_units < l.data[i] {
                return i;
            }
        }
        l.data.len()
    }

    fn is_boundary(l: &BreaksLeaf, offset: usize) -> bool {
        // TODO: binary search, data is sorted
        for i in 0..l.data.len() {
            if offset == l.data[i] {
                return true;
            } else if offset < l.data[i] {
                return false;
            }
        }
        false
    }

    fn prev(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        for i in 0..l.data.len() {
            if offset <= l.data[i] {
                if i == 0 {
                    return None;
                } else {
                    return Some(l.data[i - 1]);
                }
            }
        }
        l.data.last().cloned()
    }

    fn next(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        // TODO: binary search, data is sorted
        for i in 0..l.data.len() {
            if offset < l.data[i] {
                return Some(l.data[i]);
            }
        }
        None
    }

    fn can_fragment() -> bool {
        true
    }
}

#[derive(Copy, Clone)]
pub struct BreaksBaseMetric(());

impl Metric<BreaksInfo> for BreaksBaseMetric {
    fn measure(_: &BreaksInfo, len: usize) -> usize {
        len
    }

    fn to_base_units(_: &BreaksLeaf, in_measured_units: usize) -> usize {
        in_measured_units
    }

    fn from_base_units(_: &BreaksLeaf, in_base_units: usize) -> usize {
        in_base_units
    }

    fn is_boundary(l: &BreaksLeaf, offset: usize) -> bool {
        BreaksMetric::is_boundary(l, offset)
    }

    fn prev(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        BreaksMetric::prev(l, offset)
    }

    fn next(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        BreaksMetric::next(l, offset)
    }

    fn can_fragment() -> bool {
        true
    }
}

// Additional functions specific to breaks

impl Breaks {
    // a length with no break, useful in edit operations; for
    // other use cases, use the builder.
    pub fn new_no_break(len: usize) -> Breaks {
        let leaf = BreaksLeaf { len, data: vec![] };
        Node::from_leaf(leaf)
    }
}

pub struct BreakBuilder {
    b: TreeBuilder<BreaksInfo>,
    leaf: BreaksLeaf,
}

impl Default for BreakBuilder {
    fn default() -> BreakBuilder {
        BreakBuilder { b: TreeBuilder::new(), leaf: BreaksLeaf::default() }
    }
}

impl BreakBuilder {
    pub fn new() -> BreakBuilder {
        BreakBuilder::default()
    }

    pub fn add_break(&mut self, len: usize) {
        if self.leaf.data.len() == 64 {
            let leaf = mem::replace(&mut self.leaf, BreaksLeaf::default());
            self.b.push(Node::from_leaf(leaf));
        }
        self.leaf.len += len;
        self.leaf.data.push(self.leaf.len);
    }

    pub fn add_no_break(&mut self, len: usize) {
        self.leaf.len += len;
    }

    pub fn build(mut self) -> Breaks {
        self.b.push(Node::from_leaf(self.leaf));
        self.b.build()
    }
}

#[cfg(test)]
mod tests {
    use breaks::{BreakBuilder, BreaksInfo, BreaksLeaf, BreaksMetric};
    use interval::Interval;
    use tree::{Cursor, Node};

    fn gen(n: usize) -> Node<BreaksInfo> {
        let mut node = Node::default();
        let mut b = BreakBuilder::new();
        b.add_break(10);
        let testnode = b.build();
        if n == 1 {
            return testnode;
        }
        for _ in 0..n {
            let len = node.len();
            let empty_interval_at_end = Interval::new(len, len);
            node.edit(empty_interval_at_end, testnode.clone());
        }
        node
    }

    #[test]
    fn empty() {
        let n = gen(0);
        assert_eq!(0, n.len());
    }

    #[test]
    fn fromleaf() {
        let testnode = gen(1);
        assert_eq!(10, testnode.len());
    }

    #[test]
    fn one() {
        let testleaf = BreaksLeaf { len: 10, data: vec![10] };
        let testnode = Node::<BreaksInfo>::from_leaf(testleaf.clone());
        assert_eq!(10, testnode.len());
        let mut c = Cursor::new(&testnode, 0);
        assert_eq!(c.get_leaf().unwrap().0, &testleaf);
        assert_eq!(10, c.next::<BreaksMetric>().unwrap());
        assert!(c.next::<BreaksMetric>().is_none());
        c.set(0);
        assert!(c.is_boundary::<BreaksMetric>());
        c.set(1);
        assert!(!c.is_boundary::<BreaksMetric>());
        c.set(10);
        assert!(c.is_boundary::<BreaksMetric>());
        assert_eq!(0, c.prev::<BreaksMetric>().unwrap());
        assert!(c.prev::<BreaksMetric>().is_none());
    }

    #[test]
    fn concat() {
        let left = gen(1);
        let right = gen(1);
        let node = Node::concat(left.clone(), right);
        assert_eq!(node.len(), 20);
        let mut c = Cursor::new(&node, 0);
        assert_eq!(10, c.next::<BreaksMetric>().unwrap());
        assert_eq!(20, c.next::<BreaksMetric>().unwrap());
        assert!(c.next::<BreaksMetric>().is_none());
    }

    #[test]
    fn larger() {
        let node = gen(100);
        assert_eq!(node.len(), 1000);
    }
}
<commit_msg>Use binary search in Breaks data structure<commit_after>// Copyright 2016 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A module for representing a set of breaks, typically used for
//! storing the result of line breaking.

use interval::Interval;
use std::cmp::min;
use std::mem;
use tree::{Leaf, Metric, Node, NodeInfo, TreeBuilder};

// Breaks represents a set of indexes. A motivating use is storing line breaks.
pub type Breaks = Node<BreaksInfo>;

// Here the base units are arbitrary, but most commonly match the base units
// of the rope storing the underlying string.

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct BreaksLeaf {
    len: usize,       // measured in base units
    data: Vec<usize>, // each is a delta relative to start of leaf; sorted
}

#[derive(Clone)]
pub struct BreaksInfo(usize); // number of breaks

impl Leaf for BreaksLeaf {
    fn len(&self) -> usize {
        self.len
    }

    fn is_ok_child(&self) -> bool {
        self.data.len() >= 32
    }

    fn push_maybe_split(&mut self, other: &BreaksLeaf, iv: Interval) -> Option<BreaksLeaf> {
        //eprintln!("push_maybe_split {:?} {:?} {}", self, other, iv);
        let (start, end) = iv.start_end();
        for &v in &other.data {
            if start < v && v <= end {
                self.data.push(v - start + self.len);
            }
        }
        // the min with other.len() shouldn't be needed
        self.len += min(end, other.len()) - start;

        if self.data.len() <= 64 {
            None
        } else {
            let splitpoint = self.data.len() / 2; // number of breaks
            let splitpoint_units = self.data[splitpoint - 1];
            // TODO: use Vec::split_off(), it's nicer
            let mut new = Vec::with_capacity(self.data.len() - splitpoint);
            for i in splitpoint..self.data.len() {
                new.push(self.data[i] - splitpoint_units);
            }
            let new_len = self.len - splitpoint_units;
            self.len = splitpoint_units;
            self.data.truncate(splitpoint);
            Some(BreaksLeaf { len: new_len, data: new })
        }
    }
}

impl NodeInfo for BreaksInfo {
    type L = BreaksLeaf;

    fn accumulate(&mut self, other: &Self) {
        self.0 += other.0;
    }

    fn compute_info(l: &BreaksLeaf) -> BreaksInfo {
        BreaksInfo(l.data.len())
    }
}

#[derive(Copy, Clone)]
pub struct BreaksMetric(());

impl Metric<BreaksInfo> for BreaksMetric {
    fn measure(info: &BreaksInfo, _: usize) -> usize {
        info.0
    }

    fn to_base_units(l: &BreaksLeaf, in_measured_units: usize) -> usize {
        if in_measured_units > l.data.len() {
            l.len + 1
        } else if in_measured_units == 0 {
            0
        } else {
            l.data[in_measured_units - 1]
        }
    }

    fn from_base_units(l: &BreaksLeaf, in_base_units: usize) -> usize {
        match l.data.binary_search(&in_base_units) {
            Ok(n) => n + 1,
            Err(n) => n,
        }
    }

    fn is_boundary(l: &BreaksLeaf, offset: usize) -> bool {
        l.data.binary_search(&offset).is_ok()
    }

    fn prev(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        for i in 0..l.data.len() {
            if offset <= l.data[i] {
                if i == 0 {
                    return None;
                } else {
                    return Some(l.data[i - 1]);
                }
            }
        }
        l.data.last().cloned()
    }

    fn next(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        let n = match l.data.binary_search(&offset) {
            Ok(n) => n + 1,
            Err(n) => n,
        };

        if n == l.data.len() {
            None
        } else {
            Some(l.data[n])
        }
    }

    fn can_fragment() -> bool {
        true
    }
}

#[derive(Copy, Clone)]
pub struct BreaksBaseMetric(());

impl Metric<BreaksInfo> for BreaksBaseMetric {
    fn measure(_: &BreaksInfo, len: usize) -> usize {
        len
    }

    fn to_base_units(_: &BreaksLeaf, in_measured_units: usize) -> usize {
        in_measured_units
    }

    fn from_base_units(_: &BreaksLeaf, in_base_units: usize) -> usize {
        in_base_units
    }

    fn is_boundary(l: &BreaksLeaf, offset: usize) -> bool {
        BreaksMetric::is_boundary(l, offset)
    }

    fn prev(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        BreaksMetric::prev(l, offset)
    }

    fn next(l: &BreaksLeaf, offset: usize) -> Option<usize> {
        BreaksMetric::next(l, offset)
    }

    fn can_fragment() -> bool {
        true
    }
}

// Additional functions specific to breaks

impl Breaks {
    // a length with no break, useful in edit operations; for
    // other use cases, use the builder.
    pub fn new_no_break(len: usize) -> Breaks {
        let leaf = BreaksLeaf { len, data: vec![] };
        Node::from_leaf(leaf)
    }
}

pub struct BreakBuilder {
    b: TreeBuilder<BreaksInfo>,
    leaf: BreaksLeaf,
}

impl Default for BreakBuilder {
    fn default() -> BreakBuilder {
        BreakBuilder { b: TreeBuilder::new(), leaf: BreaksLeaf::default() }
    }
}

impl BreakBuilder {
    pub fn new() -> BreakBuilder {
        BreakBuilder::default()
    }

    pub fn add_break(&mut self, len: usize) {
        if self.leaf.data.len() == 64 {
            let leaf = mem::replace(&mut self.leaf, BreaksLeaf::default());
            self.b.push(Node::from_leaf(leaf));
        }
        self.leaf.len += len;
        self.leaf.data.push(self.leaf.len);
    }

    pub fn add_no_break(&mut self, len: usize) {
        self.leaf.len += len;
    }

    pub fn build(mut self) -> Breaks {
        self.b.push(Node::from_leaf(self.leaf));
        self.b.build()
    }
}

#[cfg(test)]
mod tests {
    use breaks::{BreakBuilder, BreaksInfo, BreaksLeaf, BreaksMetric};
    use interval::Interval;
    use tree::{Cursor, Node};

    fn gen(n: usize) -> Node<BreaksInfo> {
        let mut node = Node::default();
        let mut b = BreakBuilder::new();
        b.add_break(10);
        let testnode = b.build();
        if n == 1 {
            return testnode;
        }
        for _ in 0..n {
            let len = node.len();
            let empty_interval_at_end = Interval::new(len, len);
            node.edit(empty_interval_at_end, testnode.clone());
        }
        node
    }

    #[test]
    fn empty() {
        let n = gen(0);
        assert_eq!(0, n.len());
    }

    #[test]
    fn fromleaf() {
        let testnode = gen(1);
        assert_eq!(10, testnode.len());
    }

    #[test]
    fn one() {
        let testleaf = BreaksLeaf { len: 10, data: vec![10] };
        let testnode = Node::<BreaksInfo>::from_leaf(testleaf.clone());
        assert_eq!(10, testnode.len());
        let mut c = Cursor::new(&testnode, 0);
        assert_eq!(c.get_leaf().unwrap().0, &testleaf);
        assert_eq!(10, c.next::<BreaksMetric>().unwrap());
        assert!(c.next::<BreaksMetric>().is_none());
        c.set(0);
        assert!(c.is_boundary::<BreaksMetric>());
        c.set(1);
        assert!(!c.is_boundary::<BreaksMetric>());
        c.set(10);
        assert!(c.is_boundary::<BreaksMetric>());
        assert_eq!(0, c.prev::<BreaksMetric>().unwrap());
        assert!(c.prev::<BreaksMetric>().is_none());
    }

    #[test]
    fn concat() {
        let left = gen(1);
        let right = gen(1);
        let node = Node::concat(left.clone(), right);
        assert_eq!(node.len(), 20);
        let mut c = Cursor::new(&node, 0);
        assert_eq!(10, c.next::<BreaksMetric>().unwrap());
        assert_eq!(20, c.next::<BreaksMetric>().unwrap());
        assert!(c.next::<BreaksMetric>().is_none());
    }

    #[test]
    fn larger() {
        let node = gen(100);
        assert_eq!(node.len(), 1000);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::time::Duration;
use smallvec::SmallVec;

use device::Device;
use Error;
use OomError;
use SafeDeref;
use Success;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// A fence is used to know when a command buffer submission has finished its execution.
///
/// When a command buffer accesses a ressource, you have to ensure that the CPU doesn't access
/// the same ressource simultaneously (except for concurrent reads). Therefore in order to know
/// when the CPU can access a ressource again, a fence has to be used.
#[derive(Debug)]
pub struct Fence<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    fence: vk::Fence,

    device: D,

    // If true, we know that the `Fence` is signaled. If false, we don't know.
    // This variable exists so that we don't need to call `vkGetFenceStatus` or `vkWaitForFences`
    // multiple times.
    signaled: AtomicBool,
}

impl<D> Fence<D> where D: SafeDeref<Target = Device> {
    /// See the docs of new().
    #[inline]
    pub fn raw(device: &D) -> Result<Fence<D>, OomError>
        where D: Clone
    {
        Fence::new_impl(device, false)
    }

    /// Builds a new fence.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    #[inline]
    pub fn new(device: &D) -> Arc<Fence<D>>
        where D: Clone
    {
        Arc::new(Fence::raw(device).unwrap())
    }

    /// See the docs of signaled().
    #[inline]
    pub fn signaled_raw(device: &D) -> Result<Fence<D>, OomError>
        where D: Clone
    {
        Fence::new_impl(device, true)
    }

    /// Builds a new fence already in the "signaled" state.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    #[inline]
    pub fn signaled(device: &D) -> Arc<Fence<D>>
        where D: Clone
    {
        Arc::new(Fence::signaled_raw(device).unwrap())
    }

    fn new_impl(device: &D, signaled: bool) -> Result<Fence<D>, OomError>
        where D: Clone
    {
        let vk = device.pointers();

        let fence = unsafe {
            let infos = vk::FenceCreateInfo {
                sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO,
                pNext: ptr::null(),
                flags: if signaled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 },
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateFence(device.internal_object(), &infos,
                                             ptr::null(), &mut output)));
            output
        };

        Ok(Fence {
            fence: fence,
            device: device.clone(),
            signaled: AtomicBool::new(signaled),
        })
    }

    /// Returns true if the fence is signaled.
    #[inline]
    pub fn ready(&self) -> Result<bool, OomError> {
        unsafe {
            if self.signaled.load(Ordering::Relaxed) { return Ok(true); }

            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetFenceStatus(self.device.internal_object(),
                                                             self.fence)));
            match result {
                Success::Success => {
                    self.signaled.store(true, Ordering::Relaxed);
                    Ok(true)
                },
                Success::NotReady => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Waits until the fence is signaled, or at least until the number of nanoseconds of the
    /// timeout has elapsed.
    ///
    /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
    pub fn wait(&self, timeout: Duration) -> Result<(), FenceWaitError> {
        unsafe {
            if self.signaled.load(Ordering::Relaxed) { return Ok(()); }

            let timeout_ns = timeout.as_secs().saturating_mul(1_000_000_000)
                                              .saturating_add(timeout.subsec_nanos() as u64);

            let vk = self.device.pointers();
            let r = try!(check_errors(vk.WaitForFences(self.device.internal_object(), 1,
                                                       &self.fence, vk::TRUE, timeout_ns)));

            match r {
                Success::Success => {
                    self.signaled.store(true, Ordering::Relaxed);
                    Ok(())
                },
                Success::Timeout => {
                    Err(FenceWaitError::Timeout)
                },
                _ => unreachable!()
            }
        }
    }

    /// Waits for multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panics if not all fences belong to the same device.
    pub fn multi_wait<'a, I>(iter: I, timeout: Duration) -> Result<(), FenceWaitError>
        where I: IntoIterator<Item = &'a Fence<D>>, D: 'a
    {
        let mut device: Option<&Device> = None;

        let fences: SmallVec<[vk::Fence; 8]> = iter.into_iter().filter_map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(&*fence.device),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to wait for multiple fences that didn't belong to the \
                             same device"),
            };

            if fence.signaled.load(Ordering::Relaxed) {
                None
            } else {
                Some(fence.fence)
            }
        }).collect();

        let timeout_ns = timeout.as_secs().saturating_mul(1_000_000_000)
                                          .saturating_add(timeout.subsec_nanos() as u64);

        let r = if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                try!(check_errors(vk.WaitForFences(device.internal_object(), fences.len() as u32,
                                                   fences.as_ptr(), vk::TRUE, timeout_ns)))
            }
        } else {
            return Ok(());
        };

        match r {
            Success::Success => Ok(()),
            Success::Timeout => Err(FenceWaitError::Timeout),
            _ => unreachable!()
        }
    }

    /// Resets the fence.
    // FIXME: must synchronize the fence
    #[inline]
    pub fn reset(&self) {
        unsafe {
            let vk = self.device.pointers();
            vk.ResetFences(self.device.internal_object(), 1, &self.fence);
            self.signaled.store(false, Ordering::Relaxed);
        }
    }

    /// Resets multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panics if not all fences belong to the same device.
    pub fn multi_reset<'a, I>(iter: I)
        where I: IntoIterator<Item = &'a Fence<D>>, D: 'a
    {
        let mut device: Option<&Device> = None;

        let fences: SmallVec<[vk::Fence; 8]> = iter.into_iter().map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(&*fence.device),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to reset multiple fences that didn't belong to the same device"),
            };

            fence.signaled.store(false, Ordering::Relaxed);
            fence.fence
        }).collect();

        if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                vk.ResetFences(device.internal_object(), fences.len() as u32, fences.as_ptr());
            }
        }
    }
}

unsafe impl<D> VulkanObject for Fence<D> where D: SafeDeref<Target = Device> {
    type Object = vk::Fence;

    #[inline]
    fn internal_object(&self) -> vk::Fence {
        self.fence
    }
}

impl<D> Drop for Fence<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyFence(self.device.internal_object(), self.fence, ptr::null());
        }
    }
}

/// Error that can be returned when waiting on a fence.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FenceWaitError {
    /// Not enough memory to complete the wait.
    OomError(OomError),

    /// The specified timeout wasn't long enough.
    Timeout,

    /// The device has been lost.
    DeviceLostError,
}

impl error::Error for FenceWaitError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            FenceWaitError::OomError(_) => "no memory available",
            FenceWaitError::Timeout => "the timeout has been reached",
            FenceWaitError::DeviceLostError => "the device was lost",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            FenceWaitError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for FenceWaitError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for FenceWaitError {
    #[inline]
    fn from(err: Error) -> FenceWaitError {
        match err {
            Error::OutOfHostMemory => FenceWaitError::OomError(From::from(err)),
            Error::OutOfDeviceMemory => FenceWaitError::OomError(From::from(err)),
            Error::DeviceLost => FenceWaitError::DeviceLostError,
            _ => panic!("Unexpected error value: {}", err as i32)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use sync::Fence;

    #[test]
    fn fence_create() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::new(&device);
        assert!(!fence.ready().unwrap());
    }

    #[test]
    fn fence_create_signaled() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::signaled(&device);
        assert!(fence.ready().unwrap());
    }

    #[test]
    fn fence_signaled_wait() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::signaled(&device);
        fence.wait(Duration::new(0, 10)).unwrap();
    }

    #[test]
    fn fence_reset() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::signaled(&device);
        fence.reset();
        assert!(!fence.ready().unwrap());
    }

    #[test]
    #[should_panic = "Tried to wait for multiple fences that didn't belong to the same device"]
    fn multiwait_different_devices() {
        let (device1, _) = gfx_dev_and_queue!();
        let (device2, _) = gfx_dev_and_queue!();

        let fence1 = Fence::signaled(&device1);
        let fence2 = Fence::signaled(&device2);

        let _ = Fence::multi_wait([&*fence1, &*fence2].iter().cloned(), Duration::new(0, 10));
    }

    #[test]
    #[should_panic = "Tried to reset multiple fences that didn't belong to the same device"]
    fn multireset_different_devices() {
        let (device1, _) = gfx_dev_and_queue!();
        let (device2, _) = gfx_dev_and_queue!();

        let fence1 = Fence::signaled(&device1);
        let fence2 = Fence::signaled(&device2);

        let _ = Fence::multi_reset([&*fence1, &*fence2].iter().cloned());
    }
}
<commit_msg>Synchronize fence resets<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::time::Duration;
use smallvec::SmallVec;

use device::Device;
use Error;
use OomError;
use SafeDeref;
use Success;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// A fence is used to know when a command buffer submission has finished its execution.
///
/// When a command buffer accesses a ressource, you have to ensure that the CPU doesn't access
/// the same ressource simultaneously (except for concurrent reads). Therefore in order to know
/// when the CPU can access a ressource again, a fence has to be used.
#[derive(Debug)]
pub struct Fence<D = Arc<Device>> where D: SafeDeref<Target = Device> {
    fence: vk::Fence,

    device: D,

    // If true, we know that the `Fence` is signaled. If false, we don't know.
    // This variable exists so that we don't need to call `vkGetFenceStatus` or `vkWaitForFences`
    // multiple times.
    signaled: AtomicBool,
}

impl<D> Fence<D> where D: SafeDeref<Target = Device> {
    /// See the docs of new().
    #[inline]
    pub fn raw(device: &D) -> Result<Fence<D>, OomError>
        where D: Clone
    {
        Fence::new_impl(device, false)
    }

    /// Builds a new fence.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    #[inline]
    pub fn new(device: &D) -> Arc<Fence<D>>
        where D: Clone
    {
        Arc::new(Fence::raw(device).unwrap())
    }

    /// See the docs of signaled().
    #[inline]
    pub fn signaled_raw(device: &D) -> Result<Fence<D>, OomError>
        where D: Clone
    {
        Fence::new_impl(device, true)
    }

    /// Builds a new fence already in the "signaled" state.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    #[inline]
    pub fn signaled(device: &D) -> Arc<Fence<D>>
        where D: Clone
    {
        Arc::new(Fence::signaled_raw(device).unwrap())
    }

    fn new_impl(device: &D, signaled: bool) -> Result<Fence<D>, OomError>
        where D: Clone
    {
        let vk = device.pointers();

        let fence = unsafe {
            let infos = vk::FenceCreateInfo {
                sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO,
                pNext: ptr::null(),
                flags: if signaled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 },
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateFence(device.internal_object(), &infos,
                                             ptr::null(), &mut output)));
            output
        };

        Ok(Fence {
            fence: fence,
            device: device.clone(),
            signaled: AtomicBool::new(signaled),
        })
    }

    /// Returns true if the fence is signaled.
    #[inline]
    pub fn ready(&self) -> Result<bool, OomError> {
        unsafe {
            if self.signaled.load(Ordering::Relaxed) { return Ok(true); }

            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetFenceStatus(self.device.internal_object(),
                                                             self.fence)));
            match result {
                Success::Success => {
                    self.signaled.store(true, Ordering::Relaxed);
                    Ok(true)
                },
                Success::NotReady => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Waits until the fence is signaled, or at least until the number of nanoseconds of the
    /// timeout has elapsed.
    ///
    /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
    pub fn wait(&self, timeout: Duration) -> Result<(), FenceWaitError> {
        unsafe {
            if self.signaled.load(Ordering::Relaxed) { return Ok(()); }

            let timeout_ns = timeout.as_secs().saturating_mul(1_000_000_000)
                                              .saturating_add(timeout.subsec_nanos() as u64);

            let vk = self.device.pointers();
            let r = try!(check_errors(vk.WaitForFences(self.device.internal_object(), 1,
                                                       &self.fence, vk::TRUE, timeout_ns)));

            match r {
                Success::Success => {
                    self.signaled.store(true, Ordering::Relaxed);
                    Ok(())
                },
                Success::Timeout => {
                    Err(FenceWaitError::Timeout)
                },
                _ => unreachable!()
            }
        }
    }

    /// Waits for multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panics if not all fences belong to the same device.
    pub fn multi_wait<'a, I>(iter: I, timeout: Duration) -> Result<(), FenceWaitError>
        where I: IntoIterator<Item = &'a Fence<D>>, D: 'a
    {
        let mut device: Option<&Device> = None;

        let fences: SmallVec<[vk::Fence; 8]> = iter.into_iter().filter_map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(&*fence.device),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to wait for multiple fences that didn't belong to the \
                             same device"),
            };

            if fence.signaled.load(Ordering::Relaxed) {
                None
            } else {
                Some(fence.fence)
            }
        }).collect();

        let timeout_ns = timeout.as_secs().saturating_mul(1_000_000_000)
                                          .saturating_add(timeout.subsec_nanos() as u64);

        let r = if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                try!(check_errors(vk.WaitForFences(device.internal_object(), fences.len() as u32,
                                                   fences.as_ptr(), vk::TRUE, timeout_ns)))
            }
        } else {
            return Ok(());
        };

        match r {
            Success::Success => Ok(()),
            Success::Timeout => Err(FenceWaitError::Timeout),
            _ => unreachable!()
        }
    }

    /// Resets the fence.
    // This function takes a `&mut self` because the Vulkan API requires that the fence be
    // externally synchronized.
    #[inline]
    pub fn reset(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.ResetFences(self.device.internal_object(), 1, &self.fence);
            self.signaled.store(false, Ordering::Relaxed);
        }
    }

    /// Resets multiple fences at once.
    ///
    /// # Panic
    ///
    /// - Panics if not all fences belong to the same device.
    ///
    pub fn multi_reset<'a, I>(iter: I)
        where I: IntoIterator<Item = &'a mut Fence<D>>, D: 'a
    {
        let mut device: Option<&Device> = None;

        let fences: SmallVec<[vk::Fence; 8]> = iter.into_iter().map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(&*fence.device),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to reset multiple fences that didn't belong to the same device"),
            };

            fence.signaled.store(false, Ordering::Relaxed);
            fence.fence
        }).collect();

        if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                vk.ResetFences(device.internal_object(), fences.len() as u32, fences.as_ptr());
            }
        }
    }
}

unsafe impl<D> VulkanObject for Fence<D> where D: SafeDeref<Target = Device> {
    type Object = vk::Fence;

    #[inline]
    fn internal_object(&self) -> vk::Fence {
        self.fence
    }
}

impl<D> Drop for Fence<D> where D: SafeDeref<Target = Device> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyFence(self.device.internal_object(), self.fence, ptr::null());
        }
    }
}

/// Error that can be returned when waiting on a fence.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FenceWaitError {
    /// Not enough memory to complete the wait.
    OomError(OomError),

    /// The specified timeout wasn't long enough.
    Timeout,

    /// The device has been lost.
    DeviceLostError,
}

impl error::Error for FenceWaitError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            FenceWaitError::OomError(_) => "no memory available",
            FenceWaitError::Timeout => "the timeout has been reached",
            FenceWaitError::DeviceLostError => "the device was lost",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            FenceWaitError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for FenceWaitError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for FenceWaitError {
    #[inline]
    fn from(err: Error) -> FenceWaitError {
        match err {
            Error::OutOfHostMemory => FenceWaitError::OomError(From::from(err)),
            Error::OutOfDeviceMemory => FenceWaitError::OomError(From::from(err)),
            Error::DeviceLost => FenceWaitError::DeviceLostError,
            _ => panic!("Unexpected error value: {}", err as i32)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::time::Duration;
    use sync::Fence;

    #[test]
    fn fence_create() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::new(&device);
        assert!(!fence.ready().unwrap());
    }

    #[test]
    fn fence_create_signaled() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::signaled(&device);
        assert!(fence.ready().unwrap());
    }

    #[test]
    fn fence_signaled_wait() {
        let (device, _) = gfx_dev_and_queue!();

        let fence = Fence::signaled(&device);
        fence.wait(Duration::new(0, 10)).unwrap();
    }

    #[test]
    fn fence_reset() {
        let (device, _) = gfx_dev_and_queue!();

        let mut fence = Fence::signaled(&device);
        Arc::get_mut(&mut fence).unwrap().reset();
        assert!(!fence.ready().unwrap());
    }

    #[test]
    #[should_panic = "Tried to wait for multiple fences that didn't belong to the same device"]
    fn multiwait_different_devices() {
        let (device1, _) = gfx_dev_and_queue!();
        let (device2, _) = gfx_dev_and_queue!();

        let fence1 = Fence::signaled(&device1);
        let fence2 = Fence::signaled(&device2);

        let _ = Fence::multi_wait([&*fence1, &*fence2].iter().cloned(), Duration::new(0, 10));
    }

    #[test]
    #[should_panic = "Tried to reset multiple fences that didn't belong to the same device"]
    fn multireset_different_devices() {
        let (device1, _) = gfx_dev_and_queue!();
        let (device2, _) = gfx_dev_and_queue!();

        let mut fence1 = Fence::signaled(&device1);
        let mut fence2 = Fence::signaled(&device2);

        let _ = Fence::multi_reset(Some(Arc::get_mut(&mut fence1).unwrap()).into_iter()
                                   .chain(Some(Arc::get_mut(&mut fence2).unwrap()).into_iter()));
    }
}
<|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.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern mod fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!")
    // val is 0xC0FFEE21
    let big_val = fourcc!("foo ", big);
    // big_val is 0x21EEFFC0
}
 ```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#[crate_id = "fourcc#0.10-pre"];
#[crate_type = "rlib"];
#[crate_type = "dylib"];
#[license = "MIT/ASL2"];

#[feature(macro_registrar, managed_boxes)];

extern mod syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
#[cfg(not(test))]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(~BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

use std::ascii::AsciiCast;

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => target_endian_little(cx, sp),
        Some(Ident{ident, span}) => match token::get_ident(ident.name).get() {
            "little" => true,
            "big" => false,
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if !s.get().is_ascii() {
                    cx.span_err(expr.span, "non-ascii string literal in fourcc!");
                } else if s.get().len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
        }
    };

    let mut val = 0u32;
    if little {
        for byte in s.get().bytes_rev().take(4) {
            val = (val << 8) | (byte as u32);
        }
    } else {
        for byte in s.get().bytes().take(4) {
            val = (val << 8) | (byte as u32);
        }
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MRExpr(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_owned());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg(), meta)
}

// Fixes LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>Default fourcc! to big-endian.<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.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern mod fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!")
    // val is 0xC0FFEE21
    let big_val = fourcc!("foo ", big);
    // big_val is 0x21EEFFC0
}
 ```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#[crate_id = "fourcc#0.10-pre"];
#[crate_type = "rlib"];
#[crate_type = "dylib"];
#[license = "MIT/ASL2"];

#[feature(macro_registrar, managed_boxes)];

extern mod syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
#[cfg(not(test))]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(~BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

use std::ascii::AsciiCast;

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident.name).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if !s.get().is_ascii() {
                    cx.span_err(expr.span, "non-ascii string literal in fourcc!");
                } else if s.get().len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
        }
    };

    let mut val = 0u32;
    if little {
        for byte in s.get().bytes_rev().take(4) {
            val = (val << 8) | (byte as u32);
        }
    } else {
        for byte in s.get().bytes().take(4) {
            val = (val << 8) | (byte as u32);
        }
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MRExpr(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_owned());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg(), meta)
}

// Fixes LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use cgmath::vector::Vec2;
use core_types::{
    Size2,
    Int,
    MapPos,
};

pub struct MapPosIter {
    cursor: MapPos,
    map_size: Size2<Int>,
}

impl MapPosIter {
    pub fn new(map_size: Size2<Int>) -> MapPosIter {
        MapPosIter {
            cursor: Vec2::zero(),
            map_size: map_size,
        }
    }
}

impl Iterator<MapPos> for MapPosIter {
    fn next(&mut self) -> Option<MapPos> {
        let current_pos = if self.cursor.y > self.map_size.y {
            None
        } else {
            Some(self.cursor)
        };
        self.cursor.x += 1;
        if self.cursor.x > self.map_size.x {
            self.cursor.x = 0;
            self.cursor.y += 1;
        }
        current_pos
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Fixed MapPosIter<commit_after>// See LICENSE file for copyright and license details.

use cgmath::vector::Vec2;
use core_types::{
    Size2,
    Int,
    MapPos,
};

pub struct MapPosIter {
    cursor: MapPos,
    map_size: Size2<Int>,
}

impl MapPosIter {
    pub fn new(map_size: Size2<Int>) -> MapPosIter {
        MapPosIter {
            cursor: Vec2::zero(),
            map_size: map_size,
        }
    }
}

impl Iterator<MapPos> for MapPosIter {
    fn next(&mut self) -> Option<MapPos> {
        let current_pos = if self.cursor.y >= self.map_size.y {
            None
        } else {
            Some(self.cursor)
        };
        self.cursor.x += 1;
        if self.cursor.x >= self.map_size.x {
            self.cursor.x = 0;
            self.cursor.y += 1;
        }
        current_pos
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use errors::*;
use flate2::FlateReadExt;
use futures::Stream;
use futures::future::{BoxFuture, Future, ok};
use futures_cpupool::CpuPool;
use hyper::{self, Method, StatusCode};
use hyper::header::{ContentEncoding, ContentLength, Encoding, Headers};
use hyper::server::{Request, Response, Service};
use reproto_repository::{Checksum, Objects, to_checksum};
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::sync::{Arc, Mutex};
use tempfile;

static CHECKSUM_MISMATCH: &'static [u8] = b"Checksum Mismatch";

/// ## Read the contents of the file into a byte-vector
fn read_contents<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {
    let mut f = File::open(path)?;
    let mut content = Vec::new();
    f.read_to_end(&mut content)?;
    Ok(content)
}

pub struct ReprotoService {
    pub max_file_size: u64,
    pub pool: Arc<CpuPool>,
    pub objects: Arc<Mutex<Box<Objects>>>,
}

impl ReprotoService {
    fn no_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?))
    }

    fn gzip_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?.gz_decode()?))
    }

    fn pick_encoding(headers: &Headers) -> fn(&File) -> Result<Box<Read>> {
        if let Some(h) = headers.get::<ContentEncoding>() {
            // client encoded as gzip
            if h.0.iter().find(|encoding| **encoding == Encoding::Gzip).is_some() {
                return Self::gzip_encoding;
            }
        }

        Self::no_encoding
    }

    fn not_found() -> Response {
        Response::new().with_status(StatusCode::NotFound)
    }

    fn get_objects(&self, path: &str) -> Result<BoxFuture<Response, Error>> {
        let objects = self.objects.clone();

        let checksum =
            Checksum::from_str(&path[..]).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        // No async I/O, use pool
        Ok(self.pool
            .spawn_fn(move || {
                let result =
                    objects.lock().map_err(|_| ErrorKind::PoisonError)?.get_object(&checksum)?;

                let path = match result {
                    Some(path) => path,
                    None => return Ok(Self::not_found()),
                };

                let bytes = read_contents(path)?;

                Ok(Response::new()
                    .with_status(StatusCode::Ok)
                    .with_header(ContentLength(bytes.len() as u64))
                    .with_body(bytes))
            })
            .boxed())
    }

    fn put_objects(&self, req: Request, path: &str) -> Result<BoxFuture<Response, Error>> {
        let checksum =
            Checksum::from_str(&path[..]).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        if let Some(len) = req.headers().get::<ContentLength>() {
            if len.0 > self.max_file_size {
                return Err(ErrorKind::BadRequest("file too large").into());
            }
        } else {
            return Err(ErrorKind::BadRequest("missing content-length").into());
        }

        let encoding = Self::pick_encoding(req.headers());

        info!("Creating temporary file");
        /// TODO: make temporary
        let tmp = tempfile::tempfile()?;

        let pool = self.pool.clone();

        /// Write file in chunks as it becomes available
        let body = req.body()
            .map_err::<Error, _>(Into::into)
            .fold((pool, tmp), |(pool, mut tmp), chunk| {
                /// Write chunks on cpu-pool
                let write = pool.spawn_fn(move || {
                    tmp.write_all(chunk.as_ref())?;
                    Ok(tmp) as Result<File>
                });

                write.map(|tmp| (pool, tmp))
            })
            .map(|(_, tmp)| tmp);

        let pool = self.pool.clone();
        let objects = self.objects.clone();

        let upload = body.and_then(move |mut tmp| {
            pool.spawn_fn(move || {
                tmp.seek(SeekFrom::Start(0))?;

                let mut checksum_read = encoding(&tmp)?;
                let actual = to_checksum(&mut checksum_read)?;

                if actual != checksum {
                    info!("{} != {}", actual, checksum);

                    return Ok(Response::new()
                        .with_body(CHECKSUM_MISMATCH)
                        .with_status(StatusCode::BadRequest));
                }

                info!("Uploading object: {}", checksum);

                let mut read = encoding(&tmp)?;

                objects.lock()
                    .map_err(|_| ErrorKind::PoisonError)?
                    .put_object(&checksum, &mut read)?;

                Ok(Response::new().with_status(StatusCode::Ok))
            })
        });

        Ok(upload.boxed())
    }

    fn inner_call(&self, req: Request, path: &str) -> Result<BoxFuture<Response, Error>> {
        if let Some(len) = path.find('/') {
            match (req.method(), &path[0..len]) {
                (&Method::Get, "objects") => return self.get_objects(&path[len + 1..]),
                (&Method::Put, "objects") => return self.put_objects(req, &path[len + 1..]),
                _ => return Ok(ok(Self::not_found()).boxed()),
            }
        }

        Ok(ok(Self::not_found()).boxed())
    }

    fn handle_error(e: Error) -> Response {
        match *e.kind() {
            ErrorKind::BadRequest(ref message) => {
                return Response::new()
                    .with_status(StatusCode::BadRequest)
                    .with_header(ContentLength(message.len() as u64))
                    .with_body(*message)
            }
            _ => {
                return Response::new().with_status(StatusCode::InternalServerError);
            }
        }
    }
}

impl Service for ReprotoService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let mut path = String::from(req.path());

        // remove leading slash
        if let Some(len) = path.find('/') {
            path.drain(..len + 1);
        }

        self.inner_call(req, path.as_str())
            .unwrap_or_else(|e| ok(Self::handle_error(e)).boxed())
            .or_else(|e| ok(Self::handle_error(e)))
            .boxed()
    }
}
<commit_msg>server: use iterator for path<commit_after>use errors::*;
use flate2::FlateReadExt;
use futures::Stream;
use futures::future::{BoxFuture, Future, ok};
use futures_cpupool::CpuPool;
use hyper::{self, Method, StatusCode};
use hyper::header::{ContentEncoding, ContentLength, Encoding, Headers};
use hyper::server::{Request, Response, Service};
use reproto_repository::{Checksum, Objects, to_checksum};
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::sync::{Arc, Mutex};
use tempfile;

static CHECKSUM_MISMATCH: &'static [u8] = b"Checksum Mismatch";

/// ## Read the contents of the file into a byte-vector
fn read_contents<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {
    let mut f = File::open(path)?;
    let mut content = Vec::new();
    f.read_to_end(&mut content)?;
    Ok(content)
}

pub struct ReprotoService {
    pub max_file_size: u64,
    pub pool: Arc<CpuPool>,
    pub objects: Arc<Mutex<Box<Objects>>>,
}

impl ReprotoService {
    fn no_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?))
    }

    fn gzip_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?.gz_decode()?))
    }

    fn pick_encoding(headers: &Headers) -> fn(&File) -> Result<Box<Read>> {
        if let Some(h) = headers.get::<ContentEncoding>() {
            // client encoded as gzip
            if h.0.iter().find(|encoding| **encoding == Encoding::Gzip).is_some() {
                return Self::gzip_encoding;
            }
        }

        Self::no_encoding
    }

    fn not_found() -> Response {
        Response::new().with_status(StatusCode::NotFound)
    }

    fn get_objects<'a, I>(&self, path: I) -> Result<BoxFuture<Response, Error>>
        where I: IntoIterator<Item = &'a str>
    {
        let id = if let Some(id) = path.into_iter().next() {
            id
        } else {
            return Ok(ok(Self::not_found()).boxed());
        };

        let objects = self.objects.clone();

        let checksum = Checksum::from_str(id).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        // No async I/O, use pool
        Ok(self.pool
            .spawn_fn(move || {
                let result =
                    objects.lock().map_err(|_| ErrorKind::PoisonError)?.get_object(&checksum)?;

                let path = match result {
                    Some(path) => path,
                    None => return Ok(Self::not_found()),
                };

                let bytes = read_contents(path)?;

                Ok(Response::new()
                    .with_status(StatusCode::Ok)
                    .with_header(ContentLength(bytes.len() as u64))
                    .with_body(bytes))
            })
            .boxed())
    }

    fn put_objects<'a, I>(&self, req: Request, path: I) -> Result<BoxFuture<Response, Error>>
        where I: IntoIterator<Item = &'a str>
    {
        let id = if let Some(id) = path.into_iter().next() {
            id
        } else {
            return Ok(ok(Self::not_found()).boxed());
        };

        let checksum = Checksum::from_str(id).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        if let Some(len) = req.headers().get::<ContentLength>() {
            if len.0 > self.max_file_size {
                return Err(ErrorKind::BadRequest("file too large").into());
            }
        } else {
            return Err(ErrorKind::BadRequest("missing content-length").into());
        }

        let encoding = Self::pick_encoding(req.headers());

        info!("Creating temporary file");
        /// TODO: make temporary
        let tmp = tempfile::tempfile()?;

        let pool = self.pool.clone();

        /// Write file in chunks as it becomes available
        let body = req.body()
            .map_err::<Error, _>(Into::into)
            .fold((pool, tmp), |(pool, mut tmp), chunk| {
                /// Write chunks on cpu-pool
                let write = pool.spawn_fn(move || {
                    tmp.write_all(chunk.as_ref())?;
                    Ok(tmp) as Result<File>
                });

                write.map(|tmp| (pool, tmp))
            })
            .map(|(_, tmp)| tmp);

        let pool = self.pool.clone();
        let objects = self.objects.clone();

        let upload = body.and_then(move |mut tmp| {
            pool.spawn_fn(move || {
                tmp.seek(SeekFrom::Start(0))?;

                let mut checksum_read = encoding(&tmp)?;
                let actual = to_checksum(&mut checksum_read)?;

                if actual != checksum {
                    info!("{} != {}", actual, checksum);

                    return Ok(Response::new()
                        .with_body(CHECKSUM_MISMATCH)
                        .with_status(StatusCode::BadRequest));
                }

                info!("Uploading object: {}", checksum);

                let mut read = encoding(&tmp)?;

                objects.lock()
                    .map_err(|_| ErrorKind::PoisonError)?
                    .put_object(&checksum, &mut read)?;

                Ok(Response::new().with_status(StatusCode::Ok))
            })
        });

        Ok(upload.boxed())
    }

    fn inner_call<'a, I>(&self, req: Request, path: I) -> Result<BoxFuture<Response, Error>>
        where I: IntoIterator<Item = &'a str>
    {
        let mut it = path.into_iter();

        if let Some(part) = it.next() {
            match (req.method(), part) {
                (&Method::Get, "objects") => return self.get_objects(it),
                (&Method::Put, "objects") => return self.put_objects(req, it),
                _ => return Ok(ok(Self::not_found()).boxed()),
            }
        }

        Ok(ok(Self::not_found()).boxed())
    }

    fn handle_error(e: Error) -> Response {
        match *e.kind() {
            ErrorKind::BadRequest(ref message) => {
                return Response::new()
                    .with_status(StatusCode::BadRequest)
                    .with_header(ContentLength(message.len() as u64))
                    .with_body(*message)
            }
            _ => {
                return Response::new().with_status(StatusCode::InternalServerError);
            }
        }
    }
}

impl Service for ReprotoService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let full_path = String::from(req.path());

        let path = full_path.split('/').skip(1);

        self.inner_call(req, path)
            .unwrap_or_else(|e| ok(Self::handle_error(e)).boxed())
            .or_else(|e| ok(Self::handle_error(e)))
            .boxed()
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::mem;
use std::boxed::FnBox;
use std::sync::{Arc, Mutex, Barrier};
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use {IoObject, IoService, Handler};
use context::{Context, Transfer};
use context::stack::ProtectedFixedSizeStack;

/// The binding Arc<T> handler.
pub struct ArcHandler<T, F, R> {
    owner: Arc<T>,
    handler: F,
    marker: PhantomData<R>,
}

impl<T, F, R> Handler<R> for ArcHandler<T, F, R>
    where T: IoObject + Send + Sync + 'static,
          F: FnOnce(Arc<T>, io::Result<R>) + Send + 'static,
          R: Send + 'static,
{
    type Output = ();

    #[doc(hidden)]
    fn async_result(&self) -> Box<FnBox(*const IoService) -> Self::Output> {
        Box::new(|_|())
    }

    fn callback(self, _: &IoService, res: io::Result<R>) {
        let ArcHandler { owner, handler, marker:_ } = self;
        handler(owner, res)
    }
}

/// Provides a Arc<T> handler to asynchronous operation.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use asyncio::{IoService, bind};
/// use asyncio::ip::{Tcp, TcpSocket, TcpListener};
///
/// let io = &IoService::new();
/// let soc = Arc::new(TcpListener::new(io, Tcp::v4()).unwrap());
/// soc.async_accept(bind(|soc, res| {
///   let _: Arc<TcpListener> = soc;
///
///   if let Ok((acc, ep)) = res {
///     let _: TcpSocket = acc;
///     println!("accepted {}", ep)
///   }
/// }, &soc));
/// ```
pub fn bind<T, F, R>(handler: F, owner: &Arc<T>) -> ArcHandler<T, F, R> {
    ArcHandler {
        owner: owner.clone(),
        handler: handler,
        marker: PhantomData,
    }
}

type ArcV<T> = Arc<(UnsafeStrandCell<T>, Mutex<StrandQueue<T>>)>;

type TaskHandler<T> = Box<FnBox(*const IoService, *const ArcV<T>) + Send + 'static>;

struct UnsafeStrandCell<T> {
    data: T,
}

impl<T> UnsafeStrandCell<T> {
    unsafe fn get(&self) -> &mut T {
        &mut *(&self.data as *const _ as *mut _)
    }
}

unsafe impl<T> Send for UnsafeStrandCell<T> {}

unsafe impl<T> Sync for UnsafeStrandCell<T> {}

struct StrandQueue<T> {
    locked: bool,
    queue: VecDeque<TaskHandler<T>>,
}

impl<T> Default for StrandQueue<T> {
    fn default() -> StrandQueue<T> {
        StrandQueue {
            locked: false,
            queue: VecDeque::new(),
        }
    }
}

/// The binding Strand<T> handler.
pub struct StrandHandler<T, F, R> {
    value: ArcV<T>,
    handler: F,
    marker: PhantomData<R>,
}

impl<T, F, R> Handler<R> for StrandHandler<T, F, R>
    where T: Send + 'static,
          F: FnOnce(Strand<T>, io::Result<R>) + Send + 'static,
          R: Send + 'static,
{
    type Output = ();

    #[doc(hidden)]
    fn async_result(&self) -> Box<FnBox(*const IoService) -> Self::Output> {
        Box::new(|_|())
    }

    fn callback(self, io: &IoService, res: io::Result<R>) {
        let StrandHandler { value, handler, marker:_ } = self;
        let _ = {
            let mut owner = value.1.lock().unwrap();
            if owner.locked {
                owner.queue.push_back(Box::new(move |io: *const IoService, value: *const ArcV<T>| {
                    let strand = Strand { io: unsafe { &*io }, value: unsafe { &*value }.clone() };
                    handler(strand, res)
                }));
                return;
            }
            owner.locked = true;
        };

        handler(Strand { io: io, value: value.clone() }, res);

        while let Some(handler) = {
            let mut owner = value.1.lock().unwrap();
            if let Some(handler) = owner.queue.pop_front() {
                Some(handler)
            } else {
                owner.locked = false;
                None
            }
        } {
            handler(io, &value);
        }
    }
}

pub struct Strand<'a, T> {
    io: &'a IoService,
    value: ArcV<T>,
}

impl<'a, T> Strand<'a, T> {
    pub fn new<U: IoObject>(io: &'a U, data: T) -> Strand<'a, T> {
        Strand {
            io: io.io_service(),
            value: Arc::new((UnsafeStrandCell { data: data }, Mutex::default())),
        }
    }

    pub fn as_mut(&self) -> &mut T {
        unsafe { &mut *self.value.0.get() }
    }

    pub fn wrap<R, F>(&self, handler: F) -> StrandHandler<T, F, R>
        where F: FnOnce(Strand<T>, io::Result<R>) + Send + 'static,
              R: Send + 'static,
    {
        StrandHandler {
            value: self.value.clone(),
            handler: handler,
            marker: PhantomData,
        }
    }
}

impl<'a, T> IoObject for Strand<'a, T> {
    fn io_service(&self) -> &IoService {
        self.io
    }
}

impl<'a, T> Deref for Strand<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        unsafe { &*self.value.0.get() }
    }
}

impl<'a, T> DerefMut for Strand<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.value.0.get() }
    }
}

struct CoroData {
    context: Option<Context>,
}

impl CoroData {
    fn receiver<R>(&mut self) -> R {
        let Transfer { context, data } = self.context.take().unwrap().resume(0);
        self.context = Some(context);
        let data_opt = unsafe { &mut *(data as *mut Option<R>) };
        data_opt.take().unwrap()
    }

    fn sender<R>(&mut self, data: R) {
        let mut data_opt = Some(data);
        let Transfer { context, data:_ } = self.context.take().unwrap().resume(&mut data_opt as *mut _ as usize);
        self.context = Some(context);
    }
}

pub struct Coroutine<'a>(Strand<'a, CoroData>);

impl<'a> Coroutine<'a> {
    pub fn yield_with<R: Send + 'static>(&self) -> CoroutineHandler<R> {
        fn coro_sender<R: Send + 'static>(mut coro: Strand<CoroData>, res: io::Result<R>) {
            coro.sender(res)
        }

        CoroutineHandler {
            handler: self.0.wrap(coro_sender),
            barrier: Arc::new(Barrier::new(1)),
        }
    }
}

impl<'a> IoObject for Coroutine<'a> {
    fn io_service(&self) -> &IoService {
        self.0.io_service()
    }
}

struct InitData {
    stack: ProtectedFixedSizeStack,
    io: IoService,
    callback: Box<FnBox(&Coroutine)>,
}

pub struct CoroutineHandler<R> {
    handler: StrandHandler<CoroData, fn(Strand<CoroData>, io::Result<R>), R>,
    barrier: Arc<Barrier>,
}

impl<R: Send + 'static> Handler<R> for CoroutineHandler<R> {
    type Output = io::Result<R>;

    #[doc(hidden)]
    fn async_result(&self) -> Box<FnBox(*const IoService) -> Self::Output> {
        let value = self.handler.value.clone();
        let barrier = self.barrier.clone();
        Box::new(move |io: *const IoService| -> Self::Output {
            let mut coro = Strand {
                io: unsafe { &*io },
                value: value,
            };
            barrier.wait();
            coro.receiver()
        })
    }

    fn callback(self, io: &IoService, res: io::Result<R>) {
        self.handler.callback(io, res)
    }
}

extern "C" fn coro_entry(t: Transfer) -> ! {
    let InitData { stack, io, callback } = unsafe {
        let data_opt_ref = &mut *(t.data as *mut Option<InitData>);
        data_opt_ref.take().unwrap()
    };

    let mut coro = Coroutine(Strand::new(&io, CoroData {
        context: None,
    }));

    let context = {
        let coro_ref = &mut coro as *mut _ as usize;
        let Transfer { context, data:_ } = t.context.resume(coro_ref);

        let coro_ref = unsafe { &mut *(coro_ref as *mut Coroutine) };
        coro_ref.0.context = Some(context);

        callback.call_box((coro_ref, ));
        coro_ref.0.context.take().unwrap()
    };

    let mut stack_opt = Some(stack);
    context.resume_ontop(&mut stack_opt as *mut _ as usize, coro_exit);

    unreachable!();
}

extern "C" fn coro_exit(mut t: Transfer) -> Transfer {
    unsafe {
        // Drop the stack
        let stack_ref = &mut *(t.data as *mut Option<ProtectedFixedSizeStack>);
        let _ = stack_ref.take().unwrap();
        t.context = { mem::transmute(0usize) };
    }
    t
}

pub fn spawn<T: IoObject, F: FnOnce(&Coroutine) + 'static>(io: &T, callback: F) {
    let io = io.io_service();
    let data = InitData {
        stack: Default::default(),
        io: io.clone(),
        callback: Box::new(callback),
    };

    let context = Context::new(&data.stack, coro_entry);
    let mut data_opt = Some(data);
    let data_opt_ref = &mut data_opt as *mut _ as usize;
    let t = context.resume(data_opt_ref);

    let coro_ref = unsafe { &mut *(t.data as *mut Coroutine) };
    coro_ref.0.context = Some(t.context);

    fn coro_handler(mut coro: Strand<CoroData>, _: io::Result<()>) {
        let Transfer { context, data:_ } = coro.context.take().unwrap().resume(0);
        coro.context = Some(context);
    }
    let handler = coro_ref.0.wrap(coro_handler);
    io.post(move |io| handler.callback(io, Ok(())));
}
<commit_msg>fix race condition of Strand<commit_after>use std::io;
use std::mem;
use std::boxed::FnBox;
use std::sync::{Arc, Mutex, Barrier};
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use {IoObject, IoService, Handler};
use context::{Context, Transfer};
use context::stack::ProtectedFixedSizeStack;

/// The binding Arc<T> handler.
pub struct ArcHandler<T, F, R> {
    owner: Arc<T>,
    handler: F,
    marker: PhantomData<R>,
}

impl<T, F, R> Handler<R> for ArcHandler<T, F, R>
    where T: IoObject + Send + Sync + 'static,
          F: FnOnce(Arc<T>, io::Result<R>) + Send + 'static,
          R: Send + 'static,
{
    type Output = ();

    #[doc(hidden)]
    fn async_result(&self) -> Box<FnBox(*const IoService) -> Self::Output> {
        Box::new(|_|())
    }

    fn callback(self, _: &IoService, res: io::Result<R>) {
        let ArcHandler { owner, handler, marker:_ } = self;
        handler(owner, res)
    }
}

/// Provides a Arc<T> handler to asynchronous operation.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use asyncio::{IoService, bind};
/// use asyncio::ip::{Tcp, TcpSocket, TcpListener};
///
/// let io = &IoService::new();
/// let soc = Arc::new(TcpListener::new(io, Tcp::v4()).unwrap());
/// soc.async_accept(bind(|soc, res| {
///   let _: Arc<TcpListener> = soc;
///
///   if let Ok((acc, ep)) = res {
///     let _: TcpSocket = acc;
///     println!("accepted {}", ep)
///   }
/// }, &soc));
/// ```
pub fn bind<T, F, R>(handler: F, owner: &Arc<T>) -> ArcHandler<T, F, R> {
    ArcHandler {
        owner: owner.clone(),
        handler: handler,
        marker: PhantomData,
    }
}

type ArcV<T> = Arc<(UnsafeStrandCell<T>, Mutex<StrandQueue<T>>)>;

type TaskHandler<T> = Box<FnBox(*const IoService, *const ArcV<T>) + Send + 'static>;

struct UnsafeStrandCell<T> {
    data: T,
}

impl<T> UnsafeStrandCell<T> {
    unsafe fn get(&self) -> &mut T {
        &mut *(&self.data as *const _ as *mut _)
    }
}

unsafe impl<T> Send for UnsafeStrandCell<T> {}

unsafe impl<T> Sync for UnsafeStrandCell<T> {}

struct StrandQueue<T> {
    locked: bool,
    queue: VecDeque<TaskHandler<T>>,
}

/// The binding Strand<T> handler.
pub struct StrandHandler<T, F, R> {
    value: ArcV<T>,
    handler: F,
    marker: PhantomData<R>,
}

impl<T, F, R> Handler<R> for StrandHandler<T, F, R>
    where T: Send + 'static,
          F: FnOnce(Strand<T>, io::Result<R>) + Send + 'static,
          R: Send + 'static,
{
    type Output = ();

    #[doc(hidden)]
    fn async_result(&self) -> Box<FnBox(*const IoService) -> Self::Output> {
        Box::new(|_|())
    }

    fn callback(self, io: &IoService, res: io::Result<R>) {
        let StrandHandler { value, handler, marker:_ } = self;
        let _ = {
            let mut owner = value.1.lock().unwrap();
            if owner.locked {
                owner.queue.push_back(Box::new(move |io: *const IoService, value: *const ArcV<T>| {
                    let strand = Strand {
                        io: unsafe { &*io },
                        value: unsafe { &*value }.clone(),
                        is_new_object: false,
                    };
                    handler(strand, res)
                }));
                return;
            }
            owner.locked = true;
        };

        handler(Strand {
            io: io,
            value: value.clone(),
            is_new_object: false,
        }, res);

        while let Some(handler) = {
            let mut owner = value.1.lock().unwrap();
            if let Some(handler) = owner.queue.pop_front() {
                Some(handler)
            } else {
                owner.locked = false;
                None
            }
        } {
            handler(io, &value);
        }
    }
}

pub struct Strand<'a, T> {
    io: &'a IoService,
    value: ArcV<T>,
    is_new_object: bool,
}

impl<'a, T> Strand<'a, T> {
    pub fn new<U: IoObject>(io: &'a U, data: T) -> Strand<'a, T> {
        Strand {
            io: io.io_service(),
            value: Arc::new((UnsafeStrandCell { data: data }, Mutex::new(
                StrandQueue {
                    locked: true,
                    queue: VecDeque::new(),
                }
            ))),
            is_new_object: true,
        }
    }

    pub fn as_mut(&self) -> &mut T {
        unsafe { &mut *self.value.0.get() }
    }

    pub fn wrap<R, F>(&self, handler: F) -> StrandHandler<T, F, R>
        where F: FnOnce(Strand<T>, io::Result<R>) + Send + 'static,
              R: Send + 'static,
    {
        StrandHandler {
            value: self.value.clone(),
            handler: handler,
            marker: PhantomData,
        }
    }
}

impl<'a, T> Drop for Strand<'a, T> {
    fn drop(&mut self) {
        if self.is_new_object {
            let mut val = self.value.1.lock().unwrap();
            val.locked = false;
        }
    }
}

impl<'a, T> IoObject for Strand<'a, T> {
    fn io_service(&self) -> &IoService {
        self.io
    }
}

impl<'a, T> Deref for Strand<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        unsafe { &*self.value.0.get() }
    }
}

impl<'a, T> DerefMut for Strand<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.value.0.get() }
    }
}

struct CoroData {
    context: Option<Context>,
}

impl CoroData {
    fn receive<R>(&mut self) -> R {
        let Transfer { context, data } = self.context.take().unwrap().resume(0);
        self.context = Some(context);
        let data_opt = unsafe { &mut *(data as *mut Option<R>) };
        data_opt.take().unwrap()
    }

    fn send<R>(&mut self, data: R) {
        let mut data_opt = Some(data);
        let Transfer { context, data:_ } = self.context.take().unwrap().resume(&mut data_opt as *mut _ as usize);
        self.context = Some(context);
    }
}

pub struct Coroutine<'a>(Strand<'a, CoroData>);

impl<'a> Coroutine<'a> {
    pub fn yield_with<R: Send + 'static>(&self) -> CoroutineHandler<R> {
        fn coro_sender<R: Send + 'static>(mut coro: Strand<CoroData>, res: io::Result<R>) {
            coro.send(res)
        }

        CoroutineHandler {
            handler: self.0.wrap(coro_sender),
            barrier: Arc::new(Barrier::new(1)),
        }
    }
}

impl<'a> IoObject for Coroutine<'a> {
    fn io_service(&self) -> &IoService {
        self.0.io_service()
    }
}

struct InitData {
    stack: ProtectedFixedSizeStack,
    io: IoService,
    callback: Box<FnBox(&Coroutine)>,
}

pub struct CoroutineHandler<R> {
    handler: StrandHandler<CoroData, fn(Strand<CoroData>, io::Result<R>), R>,
    barrier: Arc<Barrier>,
}

impl<R: Send + 'static> Handler<R> for CoroutineHandler<R> {
    type Output = io::Result<R>;

    #[doc(hidden)]
    fn async_result(&self) -> Box<FnBox(*const IoService) -> Self::Output> {
        let value = self.handler.value.clone();
        let barrier = self.barrier.clone();
        Box::new(move |io: *const IoService| -> Self::Output {
            let mut coro = Strand {
                io: unsafe { &*io },
                value: value,
                is_new_object: false,
            };
            barrier.wait();
            coro.receive()
        })
    }

    fn callback(self, io: &IoService, res: io::Result<R>) {
        self.handler.callback(io, res)
    }
}

extern "C" fn coro_entry(t: Transfer) -> ! {
    let InitData { stack, io, callback } = unsafe {
        let data_opt_ref = &mut *(t.data as *mut Option<InitData>);
        data_opt_ref.take().unwrap()
    };

    // TODO: io と callback は使わないで StrandHandler を使うようにする
    let mut coro = Coroutine({
        let st = Strand::new(&io, CoroData { context: None });
        Strand {
            io: &io,
            value: st.value.clone(),
            is_new_object: false,
        }
    });

    let context = {
        let coro_ref = &mut coro as *mut _ as usize;
        let Transfer { context, data:_ } = t.context.resume(coro_ref);

        let coro_ref = unsafe { &mut *(coro_ref as *mut Coroutine) };
        coro_ref.0.context = Some(context);

        callback.call_box((coro_ref, ));
        coro_ref.0.context.take().unwrap()
    };

    let mut stack_opt = Some(stack);
    context.resume_ontop(&mut stack_opt as *mut _ as usize, coro_exit);

    unreachable!();
}

extern "C" fn coro_exit(mut t: Transfer) -> Transfer {
    unsafe {
        // Drop the stack
        let stack_ref = &mut *(t.data as *mut Option<ProtectedFixedSizeStack>);
        let _ = stack_ref.take().unwrap();
        t.context = { mem::transmute(0usize) };
    }
    t
}

pub fn spawn<T: IoObject, F: FnOnce(&Coroutine) + 'static>(io: &T, callback: F) {
    let io = io.io_service();
    let data = InitData {
        stack: Default::default(),
        io: io.clone(),
        callback: Box::new(callback),
    };

    let context = Context::new(&data.stack, coro_entry);
    let mut data_opt = Some(data);
    let data_opt_ref = &mut data_opt as *mut _ as usize;
    let t = context.resume(data_opt_ref);

    let coro_ref = unsafe { &mut *(t.data as *mut Coroutine) };
    coro_ref.0.context = Some(t.context);

    fn coro_handler(mut coro: Strand<CoroData>, _: io::Result<()>) {
        let Transfer { context, data:_ } = coro.context.take().unwrap().resume(0);
        coro.context = Some(context);
    }
    let handler = coro_ref.0.wrap(coro_handler);
    io.post(move |io| handler.callback(io, Ok(())));
}

#[test]
fn test_strand_race_condition() {
    use std::time::Duration;
    use std::thread;

    let io = &IoService::new();
    io.work(|io| {
        io.post(|io| {
            let st = Strand::new(io, 0);
            assert_eq!(*st, 0);

            let wrap = st.wrap(|mut st, _| {
                *st = 1;
                st.io_service().stop();
            });
            io.post(move |io| wrap.callback(io, Ok(())));
            thread::sleep(Duration::from_secs(1));
            assert_eq!(*st, 0);
        });

        let io = io.clone();
        thread::spawn(move || io.run());
    });
}
<|endoftext|>