<commit_before>use std::{
    any::{Any, TypeId},
    collections::{BTreeMap, HashMap},
    marker::PhantomData,
    sync::{mpsc, Arc, Mutex},
};

use crate::shell::WindowRequest;

use dces::entity::Entity;

/// Internal wrapper that stores a message inside a box.
#[derive(Debug)]
pub struct MessageBox {
    message: Box<dyn Any + Send>,
    message_type: TypeId,
    target: Entity,
}

impl MessageBox {
    /// Creates a new `MessageBox`.
    pub fn new<M: Any + Send>(message: M, target: Entity) -> Self {
        MessageBox {
            message: Box::new(message),
            target,
            message_type: TypeId::of::<M>(),
        }
    }

    /// Check if the given type is the type of the message.
    pub fn is_type<M: Any>(&self) -> bool {
        self.message_type == TypeId::of::<M>()
    }

    /// Returns the type of the event.
    pub fn message_type(&self) -> TypeId {
        self.message_type
    }

    /// Downcasts the box to an concrete message.
    pub fn downcast<M: Any>(self) -> Result<M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(*self.message.downcast::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }

    /// Downcasts the box as reference of an concrete message.
    pub fn downcast_ref<M: Any>(&self) -> Result<&M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(&*self.message.downcast_ref::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }
}

/// The `MessageAdapter` provides a thread save entry point to sent
/// and read messages inside widget entities. They are processed inside the
/// method `message` defined in each widgets `State` code.
///
/// # Example
///
#[doc = "The following code example ..."]
/// ```rust
/// // State
/// fn say_hello(entity: Entity, message_adapter: MessageAdapter) {
///     message_adapter.send_message(String::from("Hello rustician"), entity);
///     message_adapter.send_message(String::from("Did you got my message?"), entity);
/// }
///
/// impl Mystate {}
///
/// // implementation fo the State
/// impl State for MyState {
///     fn message(&mut self, mut messages: MessageReader, _registry: &mut Registry, _ctx: &mut Context) {
///         for message in messages.read::<String>() {
///         println!("{}", message);
///     }
/// }
/// ```
#[doc = "will print two lines to stdout:"]
#[doc = "```text"]
#[doc = "$ Hello rustician,"]
#[doc = "$ Did you got my message?"]
#[derive(Clone, Debug)]
pub struct MessageAdapter {
    messages: Arc<Mutex<BTreeMap<Entity, HashMap<TypeId, Vec<MessageBox>>>>>,
    window_sender: mpsc::Sender<WindowRequest>,
}

impl MessageAdapter {
    /// Creates a new message adapter
    pub fn new(window_sender: mpsc::Sender<WindowRequest>) -> Self {
        MessageAdapter {
            messages: Arc::new(Mutex::new(BTreeMap::new())),
            window_sender,
        }
    }

    /// Send a new message to the message pipeline.
    pub fn send_message<M: Any + Send>(&self, message: M, target: Entity) {
        if !self.messages.lock().unwrap().contains_key(&target) {
            self.messages
                .lock()
                .expect("MessageAdapter::send_message: Cannot lock messages.")
                .insert(target, HashMap::new());
        }

        let type_id = TypeId::of::<M>();

        if !self
            .messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.")
            .get(&target)
            .unwrap()
            .contains_key(&type_id)
        {
            self.messages
                .lock()
                .expect("MessageAdapter::send_message: Cannot lock messages.")
                .get_mut(&target)
                .unwrap()
                .insert(type_id, vec![]);
        }

        self.messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.")
            .get_mut(&target)
            .unwrap()
            .get_mut(&type_id)
            .unwrap()
            .push(MessageBox::new(message, target));

        self.window_sender
            .send(WindowRequest::Redraw)
            .expect("MessageAdapter::send_message: Cannot send redraw request.");
    }

    /// Returns a list of entities that has messages.
    pub(crate) fn entities(&self) -> Vec<Entity> {
        self.messages
            .lock()
            .expect("MessageAdapter::entities: Cannot lock messages.")
            .keys()
            .cloned()
            .collect()
    }

    /// Removes all messages for the given target entity. This is used
    /// to remove messages for entities that does not have a `State`
    /// to read the messages.
    pub(crate) fn remove_message_for_entity(&self, target: Entity) {
        self.messages
            .lock()
            .expect("MessageAdapter::remove_message_for_entity: Cannot lock messages.")
            .remove(&target);
    }

    /// Returns the number of messages in the queue.
    pub fn len(&self) -> usize {
        self.messages
            .lock()
            .expect("MessageAdapter::len: Cannot lock messages.")
            .len()
    }

    /// Returns `true` if the event message contains no events.
    pub fn is_empty(&self) -> bool {
        self.messages
            .lock()
            .expect("MessageAdapter::is_empty: Cannot lock messages.")
            .is_empty()
    }

    /// Returns a message reader for the given entity. Moves all
    /// messages for the entity from the adapter to the reader.
    pub(crate) fn message_reader(&self, entity: Entity) -> MessageReader {
        let messages = if let Some(messages) = self
            .messages
            .lock()
            .expect("MessageAdapter::message_reader: Cannot lock messages.")
            .remove(&entity)
        {
            messages
        } else {
            HashMap::new()
        };

        MessageReader::new(messages, entity)
    }
}

/// The `MessageReader` is used to access the messages of a widget.
pub struct MessageReader {
    messages: HashMap<TypeId, Vec<MessageBox>>,
    target: Entity,
}

impl MessageReader {
    /// Creates a new message reader.
    pub fn new(messages: HashMap<TypeId, Vec<MessageBox>>, target: Entity) -> Self {
        MessageReader { messages, target }
    }

    /// Returns the target entity of the reader.
    pub fn entity(&self) -> Entity {
        self.target
    }

    /// Returns `true` if the reader contains message for the specified type.
    pub fn contains_type<M: Any>(&self) -> bool {
        self.messages.contains_key(&TypeId::of::<M>())
    }

    /// Returns `true` if the reader contains no messages.
    pub fn is_empty(&self) -> bool {
        self.messages.is_empty()
    }

    /// Returns a message iterator for the given message type.
    pub fn read<M: Any + Send>(&mut self) -> MessageIterator<M> {
        let messages = if let Some(messages) = self.messages.remove(&TypeId::of::<M>()) {
            messages
        } else {
            vec![]
        };

        MessageIterator::new(messages)
    }
}

/// Iterator of messages.
#[derive(Debug)]
pub struct MessageIterator<M>
where
    M: Any + Send,
{
    messages: Vec<MessageBox>,
    _phantom: PhantomData<M>,
}

impl<M> MessageIterator<M>
where
    M: Any + Send,
{
    pub(crate) fn new(messages: Vec<MessageBox>) -> Self {
        MessageIterator {
            messages,
            _phantom: PhantomData::default(),
        }
    }
}

impl<M> Iterator for MessageIterator<M>
where
    M: Any + Send,
{
    type Item = M;

    fn next(&mut self) -> Option<Self::Item> {
        if self.messages.is_empty() {
            return None;
        }

        // unwrap is ok because only messages of the same type should
        // be stored in the vec
        Some(self.messages.remove(0).downcast::<M>().unwrap())
    }
}
<commit_msg>orbtk_core: bug correction in message_adapter documentation<commit_after>use std::{
    any::{Any, TypeId},
    collections::{BTreeMap, HashMap},
    marker::PhantomData,
    sync::{mpsc, Arc, Mutex},
};

use crate::shell::WindowRequest;

use dces::entity::Entity;

/// Internal wrapper that stores a message inside a box.
#[derive(Debug)]
pub struct MessageBox {
    message: Box<dyn Any + Send>,
    message_type: TypeId,
    target: Entity,
}

impl MessageBox {
    /// Creates a new `MessageBox`.
    pub fn new<M: Any + Send>(message: M, target: Entity) -> Self {
        MessageBox {
            message: Box::new(message),
            target,
            message_type: TypeId::of::<M>(),
        }
    }

    /// Check if the given type is the type of the message.
    pub fn is_type<M: Any>(&self) -> bool {
        self.message_type == TypeId::of::<M>()
    }

    /// Returns the type of the event.
    pub fn message_type(&self) -> TypeId {
        self.message_type
    }

    /// Downcasts the box to an concrete message.
    pub fn downcast<M: Any>(self) -> Result<M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(*self.message.downcast::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }

    /// Downcasts the box as reference of an concrete message.
    pub fn downcast_ref<M: Any>(&self) -> Result<&M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(&*self.message.downcast_ref::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }
}

/// The `MessageAdapter` provides a thread save entry point to sent
/// and read messages inside widget entities. They are processed inside the
/// method `message` defined in each widgets `State` code.
///
/// # Example
///
/// ```rust
/// // State
/// fn say_hello(entity: Entity, message_adapter: MessageAdapter) {
///     message_adapter.send_message(String::from("Hello rustician"), entity);
///     message_adapter.send_message(String::from("Did you recieve my message?"), entity);
/// }
///
/// impl MyState {}
///
/// // implementation for the State
/// impl State for MyState {
///     fn message(&mut self, mut messages: MessageReader, _registry: &mut Registry, _ctx: &mut Context) {
///         for message in messages.read::<String>() {
///             println!("{}", message);
///         }
///     }
/// }
/// ```
///
/// The example code snippet above will print two lines to stdout:
///
/// ```text
/// $ Hello rustician,
/// $  Did you receive my message?
/// ```
#[derive(Clone, Debug)]
pub struct MessageAdapter {
    messages: Arc<Mutex<BTreeMap<Entity, HashMap<TypeId, Vec<MessageBox>>>>>,
    window_sender: mpsc::Sender<WindowRequest>,
}

impl MessageAdapter {
    /// Creates a new message adapter
    pub fn new(window_sender: mpsc::Sender<WindowRequest>) -> Self {
        MessageAdapter {
            messages: Arc::new(Mutex::new(BTreeMap::new())),
            window_sender,
        }
    }

    /// Send a new message to the message pipeline.
    pub fn send_message<M: Any + Send>(&self, message: M, target: Entity) {
        if !self.messages.lock().unwrap().contains_key(&target) {
            self.messages
                .lock()
                .expect("MessageAdapter::send_message: Cannot lock messages.")
                .insert(target, HashMap::new());
        }

        let type_id = TypeId::of::<M>();

        if !self
            .messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.")
            .get(&target)
            .unwrap()
            .contains_key(&type_id)
        {
            self.messages
                .lock()
                .expect("MessageAdapter::send_message: Cannot lock messages.")
                .get_mut(&target)
                .unwrap()
                .insert(type_id, vec![]);
        }

        self.messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.")
            .get_mut(&target)
            .unwrap()
            .get_mut(&type_id)
            .unwrap()
            .push(MessageBox::new(message, target));

        self.window_sender
            .send(WindowRequest::Redraw)
            .expect("MessageAdapter::send_message: Cannot send redraw request.");
    }

    /// Returns a list of entities that has messages.
    pub(crate) fn entities(&self) -> Vec<Entity> {
        self.messages
            .lock()
            .expect("MessageAdapter::entities: Cannot lock messages.")
            .keys()
            .cloned()
            .collect()
    }

    /// Removes all messages for the given target entity. This is used
    /// to remove messages for entities that does not have a `State`
    /// to read the messages.
    pub(crate) fn remove_message_for_entity(&self, target: Entity) {
        self.messages
            .lock()
            .expect("MessageAdapter::remove_message_for_entity: Cannot lock messages.")
            .remove(&target);
    }

    /// Returns the number of messages in the queue.
    pub fn len(&self) -> usize {
        self.messages
            .lock()
            .expect("MessageAdapter::len: Cannot lock messages.")
            .len()
    }

    /// Returns `true` if the event message contains no events.
    pub fn is_empty(&self) -> bool {
        self.messages
            .lock()
            .expect("MessageAdapter::is_empty: Cannot lock messages.")
            .is_empty()
    }

    /// Returns a message reader for the given entity. Moves all
    /// messages for the entity from the adapter to the reader.
    pub(crate) fn message_reader(&self, entity: Entity) -> MessageReader {
        let messages = if let Some(messages) = self
            .messages
            .lock()
            .expect("MessageAdapter::message_reader: Cannot lock messages.")
            .remove(&entity)
        {
            messages
        } else {
            HashMap::new()
        };

        MessageReader::new(messages, entity)
    }
}

/// The `MessageReader` is used to access the messages of a widget.
pub struct MessageReader {
    messages: HashMap<TypeId, Vec<MessageBox>>,
    target: Entity,
}

impl MessageReader {
    /// Creates a new message reader.
    pub fn new(messages: HashMap<TypeId, Vec<MessageBox>>, target: Entity) -> Self {
        MessageReader { messages, target }
    }

    /// Returns the target entity of the reader.
    pub fn entity(&self) -> Entity {
        self.target
    }

    /// Returns `true` if the reader contains message for the specified type.
    pub fn contains_type<M: Any>(&self) -> bool {
        self.messages.contains_key(&TypeId::of::<M>())
    }

    /// Returns `true` if the reader contains no messages.
    pub fn is_empty(&self) -> bool {
        self.messages.is_empty()
    }

    /// Returns a message iterator for the given message type.
    pub fn read<M: Any + Send>(&mut self) -> MessageIterator<M> {
        let messages = if let Some(messages) = self.messages.remove(&TypeId::of::<M>()) {
            messages
        } else {
            vec![]
        };

        MessageIterator::new(messages)
    }
}

/// Iterator of messages.
#[derive(Debug)]
pub struct MessageIterator<M>
where
    M: Any + Send,
{
    messages: Vec<MessageBox>,
    _phantom: PhantomData<M>,
}

impl<M> MessageIterator<M>
where
    M: Any + Send,
{
    pub(crate) fn new(messages: Vec<MessageBox>) -> Self {
        MessageIterator {
            messages,
            _phantom: PhantomData::default(),
        }
    }
}

impl<M> Iterator for MessageIterator<M>
where
    M: Any + Send,
{
    type Item = M;

    fn next(&mut self) -> Option<Self::Item> {
        if self.messages.is_empty() {
            return None;
        }

        // unwrap is ok because only messages of the same type should
        // be stored in the vec
        Some(self.messages.remove(0).downcast::<M>().unwrap())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::iter;
use std::slice;

use htslib;

use bam;
use bam::record;

/// Iterator over alignments of a pileup.
pub type Alignments<'a> = iter::Map<
    slice::Iter<'a, htslib::bam_pileup1_t>,
    fn(&'a htslib::bam_pileup1_t) -> Alignment<'a>,
>;

/// A pileup over one genomic position.
#[derive(Debug)]
pub struct Pileup {
    inner: *const htslib::bam_pileup1_t,
    depth: u32,
    tid: u32,
    pos: u32,
}

impl Pileup {
    pub fn tid(&self) -> u32 {
        self.tid
    }

    pub fn pos(&self) -> u32 {
        self.pos
    }

    pub fn depth(&self) -> u32 {
        self.depth
    }

    pub fn alignments(&self) -> Alignments {
        self.inner().iter().map(Alignment::new)
    }

    fn inner(&self) -> &[htslib::bam_pileup1_t] {
        unsafe {
            slice::from_raw_parts(
                self.inner as *mut htslib::bam_pileup1_t,
                self.depth as usize,
            )
        }
    }
}

/// An aligned read in a pileup.
pub struct Alignment<'a> {
    inner: &'a htslib::bam_pileup1_t,
}

impl<'a> fmt::Debug for Alignment<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Alignment")
    }
}

impl<'a> Alignment<'a> {
    pub fn new(inner: &'a htslib::bam_pileup1_t) -> Self {
        Alignment { inner: inner }
    }

    /// Position within the read. None if either `is_del` or `is_refskip`.
    pub fn qpos(&self) -> Option<usize> {
        if self.is_del() || self.is_refskip() {
            // there is no alignment position in such a case
            None
        } else {
            Some(self.inner.qpos as usize)
        }
    }

    /// Insertion, deletion (with length) if indel starts at next base or None otherwise.
    pub fn indel(&self) -> Indel {
        match self.inner.indel {
            len if len < 0 => Indel::Del(-len as u32),
            len if len > 0 => Indel::Ins(len as u32),
            _ => Indel::None,
        }
    }

    /// Whether there is a deletion in the alignment at this position.
    pub fn is_del(&self) -> bool {
        self.inner.is_del() != 0
    }

    /// Whether the alignment starts at this position.
    pub fn is_head(&self) -> bool {
        self.inner.is_head() != 0
    }

    /// Whether the alignment ends at this position.
    pub fn is_tail(&self) -> bool {
        self.inner.is_tail() != 0
    }

    /// Whether this position is marked as refskip in the CIGAR string.
    pub fn is_refskip(&self) -> bool {
        self.inner.is_refskip() != 0
    }

    /// The corresponding record.
    pub fn record(&self) -> record::Record {
        record::Record::from_inner(self.inner.b)
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub enum Indel {
    Ins(u32),
    Del(u32),
    None,
}

/// Iterator over pileups.
#[derive(Debug)]
pub struct Pileups<'a, R: 'a + bam::Read> {
    #[allow(dead_code)]
    reader: &'a mut R,
    itr: htslib::bam_plp_t,
}

impl<'a, R: bam::Read> Pileups<'a, R> {
    pub fn new(reader: &'a mut R, itr: htslib::bam_plp_t) -> Self {
        Pileups {
            reader: reader,
            itr: itr,
        }
    }

    /// Warning: because htslib internally uses signed integer for depth this method
    /// will panic if `depth` exceeds `i32::max_value()`.
    pub fn set_max_depth(&mut self, depth: u32) {
        if depth > i32::max_value() as u32 {
            panic!("Maximum value for pileup depth is {} but {} was provided", i32::max_value(), depth)
        }
        let intdepth = depth as i32;
        unsafe {
            htslib::bam_plp_set_maxcnt(self.itr, intdepth);
        }
    }
}

impl<'a, R: bam::Read> Iterator for Pileups<'a, R> {
    type Item = Result<Pileup, PileupError>;

    fn next(&mut self) -> Option<Result<Pileup, PileupError>> {
        let (mut tid, mut pos, mut depth) = (0i32, 0i32, 0i32);
        let inner = unsafe { htslib::bam_plp_auto(self.itr, &mut tid, &mut pos, &mut depth) };

        match inner.is_null() {
            true if depth == -1 => Some(Err(PileupError::Some)),
            true => None,
            false => Some(Ok(Pileup {
                inner: inner,
                depth: depth as u32,
                tid: tid as u32,
                pos: pos as u32,
            })),
        }
    }
}

impl<'a, R: bam::Read> Drop for Pileups<'a, R> {
    fn drop(&mut self) {
        unsafe {
            htslib::bam_plp_reset(self.itr);
            htslib::bam_plp_destroy(self.itr);
        }
    }
}

quick_error! {
    #[derive(Debug, Clone)]
    pub enum PileupError {
        Some {
            description("error generating pileup")
        }
    }
}

#[cfg(test)]
mod tests {

    use bam;
    use prelude::*;

    #[test]
    fn test_max_pileup() {
        let mut bam = bam::Reader::from_path(&"test/test.bam").unwrap();
        let mut p = bam.pileup();
        p.set_max_depth(0u32);
        p.set_max_depth(800u32);

    }

    #[test]
    #[should_panic]
    fn test_max_pileup_to_high() {
        let mut bam = bam::Reader::from_path(&"test/test.bam").unwrap();
        let mut p = bam.pileup();
        p.set_max_depth((i32::max_value() as u32) + 1);
    }

}
<commit_msg>fix formatting<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::iter;
use std::slice;

use htslib;

use bam;
use bam::record;

/// Iterator over alignments of a pileup.
pub type Alignments<'a> = iter::Map<
    slice::Iter<'a, htslib::bam_pileup1_t>,
    fn(&'a htslib::bam_pileup1_t) -> Alignment<'a>,
>;

/// A pileup over one genomic position.
#[derive(Debug)]
pub struct Pileup {
    inner: *const htslib::bam_pileup1_t,
    depth: u32,
    tid: u32,
    pos: u32,
}

impl Pileup {
    pub fn tid(&self) -> u32 {
        self.tid
    }

    pub fn pos(&self) -> u32 {
        self.pos
    }

    pub fn depth(&self) -> u32 {
        self.depth
    }

    pub fn alignments(&self) -> Alignments {
        self.inner().iter().map(Alignment::new)
    }

    fn inner(&self) -> &[htslib::bam_pileup1_t] {
        unsafe {
            slice::from_raw_parts(
                self.inner as *mut htslib::bam_pileup1_t,
                self.depth as usize,
            )
        }
    }
}

/// An aligned read in a pileup.
pub struct Alignment<'a> {
    inner: &'a htslib::bam_pileup1_t,
}

impl<'a> fmt::Debug for Alignment<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Alignment")
    }
}

impl<'a> Alignment<'a> {
    pub fn new(inner: &'a htslib::bam_pileup1_t) -> Self {
        Alignment { inner: inner }
    }

    /// Position within the read. None if either `is_del` or `is_refskip`.
    pub fn qpos(&self) -> Option<usize> {
        if self.is_del() || self.is_refskip() {
            // there is no alignment position in such a case
            None
        } else {
            Some(self.inner.qpos as usize)
        }
    }

    /// Insertion, deletion (with length) if indel starts at next base or None otherwise.
    pub fn indel(&self) -> Indel {
        match self.inner.indel {
            len if len < 0 => Indel::Del(-len as u32),
            len if len > 0 => Indel::Ins(len as u32),
            _ => Indel::None,
        }
    }

    /// Whether there is a deletion in the alignment at this position.
    pub fn is_del(&self) -> bool {
        self.inner.is_del() != 0
    }

    /// Whether the alignment starts at this position.
    pub fn is_head(&self) -> bool {
        self.inner.is_head() != 0
    }

    /// Whether the alignment ends at this position.
    pub fn is_tail(&self) -> bool {
        self.inner.is_tail() != 0
    }

    /// Whether this position is marked as refskip in the CIGAR string.
    pub fn is_refskip(&self) -> bool {
        self.inner.is_refskip() != 0
    }

    /// The corresponding record.
    pub fn record(&self) -> record::Record {
        record::Record::from_inner(self.inner.b)
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub enum Indel {
    Ins(u32),
    Del(u32),
    None,
}

/// Iterator over pileups.
#[derive(Debug)]
pub struct Pileups<'a, R: 'a + bam::Read> {
    #[allow(dead_code)]
    reader: &'a mut R,
    itr: htslib::bam_plp_t,
}

impl<'a, R: bam::Read> Pileups<'a, R> {
    pub fn new(reader: &'a mut R, itr: htslib::bam_plp_t) -> Self {
        Pileups {
            reader: reader,
            itr: itr,
        }
    }

    /// Warning: because htslib internally uses signed integer for depth this method
    /// will panic if `depth` exceeds `i32::max_value()`.
    pub fn set_max_depth(&mut self, depth: u32) {
        if depth > i32::max_value() as u32 {
            panic!(
                "Maximum value for pileup depth is {} but {} was provided",
                i32::max_value(),
                depth
            )
        }
        let intdepth = depth as i32;
        unsafe {
            htslib::bam_plp_set_maxcnt(self.itr, intdepth);
        }
    }
}

impl<'a, R: bam::Read> Iterator for Pileups<'a, R> {
    type Item = Result<Pileup, PileupError>;

    fn next(&mut self) -> Option<Result<Pileup, PileupError>> {
        let (mut tid, mut pos, mut depth) = (0i32, 0i32, 0i32);
        let inner = unsafe { htslib::bam_plp_auto(self.itr, &mut tid, &mut pos, &mut depth) };

        match inner.is_null() {
            true if depth == -1 => Some(Err(PileupError::Some)),
            true => None,
            false => Some(Ok(Pileup {
                inner: inner,
                depth: depth as u32,
                tid: tid as u32,
                pos: pos as u32,
            })),
        }
    }
}

impl<'a, R: bam::Read> Drop for Pileups<'a, R> {
    fn drop(&mut self) {
        unsafe {
            htslib::bam_plp_reset(self.itr);
            htslib::bam_plp_destroy(self.itr);
        }
    }
}

quick_error! {
    #[derive(Debug, Clone)]
    pub enum PileupError {
        Some {
            description("error generating pileup")
        }
    }
}

#[cfg(test)]
mod tests {

    use bam;
    use prelude::*;

    #[test]
    fn test_max_pileup() {
        let mut bam = bam::Reader::from_path(&"test/test.bam").unwrap();
        let mut p = bam.pileup();
        p.set_max_depth(0u32);
        p.set_max_depth(800u32);
    }

    #[test]
    #[should_panic]
    fn test_max_pileup_to_high() {
        let mut bam = bam::Reader::from_path(&"test/test.bam").unwrap();
        let mut p = bam.pileup();
        p.set_max_depth((i32::max_value() as u32) + 1);
    }

}
<|endoftext|>


<commit_before>#![warn(clippy::all, rust_2018_idioms)]
#![allow(clippy::unknown_clippy_lints)]

use cargo_registry::{boot, App, Env};
use std::{
    borrow::Cow,
    fs::File,
    sync::{mpsc::channel, Arc, Mutex},
    thread,
    time::Duration,
};

use civet::Server as CivetServer;
use conduit_hyper::Service;
use futures_util::future::FutureExt;
use reqwest::blocking::Client;
use sentry::{ClientOptions, IntoDsn};

const CORE_THREADS: usize = 4;

#[allow(clippy::large_enum_variant)]
enum Server {
    Civet(CivetServer),
    Hyper(tokio::runtime::Runtime, tokio::task::JoinHandle<()>),
}

use Server::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let _sentry = dotenv::var("SENTRY_DSN_API")
        .ok()
        .into_dsn()
        .expect("SENTRY_DSN_API is not a valid Sentry DSN value")
        .map(|dsn| {
            let mut opts = ClientOptions::from(dsn);
            opts.environment = Some(
                dotenv::var("SENTRY_ENV_API")
                    .map(Cow::Owned)
                    .expect("SENTRY_ENV_API must be set when using SENTRY_DSN_API"),
            );

            if let Ok(commit) = dotenv::var("HEROKU_SLUG_COMMIT") {
                opts.release = Some(commit.into());
            }

            sentry::init(opts)
        });

    // Initialize logging
    env_logger::init();

    let config = cargo_registry::Config::default();
    let client = Client::new();

    let app = App::new(config.clone(), Some(client));
    let app = cargo_registry::build_handler(Arc::new(app));

    // On every server restart, ensure the categories available in the database match
    // the information in *src/categories.toml*.
    let categories_toml = include_str!("../boot/categories.toml");
    boot::categories::sync(categories_toml).unwrap();

    let heroku = dotenv::var("HEROKU").is_ok();
    let fastboot = dotenv::var("USE_FASTBOOT").is_ok();

    let port = if heroku {
        8888
    } else {
        dotenv::var("PORT")
            .ok()
            .and_then(|s| s.parse().ok())
            .unwrap_or(8888)
    };
    let threads = dotenv::var("SERVER_THREADS")
        .map(|s| s.parse().expect("SERVER_THREADS was not a valid number"))
        .unwrap_or_else(|_| {
            if config.env == Env::Development {
                5
            } else {
                // A large default because this can be easily changed via env and in production we
                // want the logging middleware to accurately record the start time.
                500
            }
        });

    let server = if dotenv::var("WEB_USE_CIVET").is_err() {
        use tokio::io::AsyncWriteExt;
        use tokio::signal::unix::{signal, SignalKind};

        println!("Booting with a hyper based server");

        let mut rt = tokio::runtime::Builder::new()
            .threaded_scheduler()
            .enable_all()
            .core_threads(CORE_THREADS)
            .max_threads(threads as usize + CORE_THREADS)
            .build()
            .unwrap();

        let handler = Arc::new(conduit_hyper::BlockingHandler::new(app));
        let make_service =
            hyper::service::make_service_fn(move |socket: &hyper::server::conn::AddrStream| {
                let addr = socket.remote_addr();
                let handler = handler.clone();
                async move { Service::from_blocking(handler, addr) }
            });

        let addr = ([127, 0, 0, 1], port).into();
        #[allow(clippy::async_yields_async)]
        let server = rt.block_on(async { hyper::Server::bind(&addr).serve(make_service) });

        let mut sig_int = rt.block_on(async { signal(SignalKind::interrupt()) })?;
        let mut sig_term = rt.block_on(async { signal(SignalKind::terminate()) })?;

        let server = server.with_graceful_shutdown(async move {
            // Wait for either signal
            futures_util::select! {
                _ = sig_int.recv().fuse() => (),
                _ = sig_term.recv().fuse() => (),
            };
            let mut stdout = tokio::io::stdout();
            stdout.write_all(b"Starting graceful shutdown\n").await.ok();
        });

        let server = rt.spawn(async { server.await.unwrap() });
        Hyper(rt, server)
    } else {
        println!("Booting with a civet based server");
        let mut cfg = civet::Config::new();
        cfg.port(port).threads(threads).keep_alive(true);
        Civet(CivetServer::start(cfg, app).unwrap())
    };

    println!("listening on port {}", port);

    // Give tokio a chance to spawn the first worker thread
    thread::sleep(Duration::from_millis(10));

    // Creating this file tells heroku to tell nginx that the application is ready
    // to receive traffic.
    if heroku {
        let path = if fastboot {
            "/tmp/backend-initialized"
        } else {
            "/tmp/app-initialized"
        };
        println!("Writing to {}", path);
        File::create(path).unwrap();
    }

    // Block the main thread until the server has shutdown
    match server {
        Hyper(mut rt, server) => {
            rt.block_on(async { server.await.unwrap() });
        }
        Civet(server) => {
            let (tx, rx) = channel::<()>();
            ctrlc_handler(move || tx.send(()).unwrap_or(()));
            rx.recv().unwrap();
            drop(server);
        }
    }

    println!("Server has gracefully shutdown!");
    Ok(())
}

fn ctrlc_handler<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    let call_once = Mutex::new(Some(f));

    ctrlc::set_handler(move || {
        if let Some(f) = call_once.lock().unwrap().take() {
            println!("Starting graceful shutdown");
            f();
        } else {
            println!("Already sent signal to start graceful shutdown");
        }
    })
    .unwrap();
}
<commit_msg>Simplify `opts.release` assignment<commit_after>#![warn(clippy::all, rust_2018_idioms)]
#![allow(clippy::unknown_clippy_lints)]

use cargo_registry::{boot, App, Env};
use std::{
    borrow::Cow,
    fs::File,
    sync::{mpsc::channel, Arc, Mutex},
    thread,
    time::Duration,
};

use civet::Server as CivetServer;
use conduit_hyper::Service;
use futures_util::future::FutureExt;
use reqwest::blocking::Client;
use sentry::{ClientOptions, IntoDsn};

const CORE_THREADS: usize = 4;

#[allow(clippy::large_enum_variant)]
enum Server {
    Civet(CivetServer),
    Hyper(tokio::runtime::Runtime, tokio::task::JoinHandle<()>),
}

use Server::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let _sentry = dotenv::var("SENTRY_DSN_API")
        .ok()
        .into_dsn()
        .expect("SENTRY_DSN_API is not a valid Sentry DSN value")
        .map(|dsn| {
            let mut opts = ClientOptions::from(dsn);
            opts.environment = Some(
                dotenv::var("SENTRY_ENV_API")
                    .map(Cow::Owned)
                    .expect("SENTRY_ENV_API must be set when using SENTRY_DSN_API"),
            );

            opts.release = dotenv::var("HEROKU_SLUG_COMMIT").ok().map(Into::into);

            sentry::init(opts)
        });

    // Initialize logging
    env_logger::init();

    let config = cargo_registry::Config::default();
    let client = Client::new();

    let app = App::new(config.clone(), Some(client));
    let app = cargo_registry::build_handler(Arc::new(app));

    // On every server restart, ensure the categories available in the database match
    // the information in *src/categories.toml*.
    let categories_toml = include_str!("../boot/categories.toml");
    boot::categories::sync(categories_toml).unwrap();

    let heroku = dotenv::var("HEROKU").is_ok();
    let fastboot = dotenv::var("USE_FASTBOOT").is_ok();

    let port = if heroku {
        8888
    } else {
        dotenv::var("PORT")
            .ok()
            .and_then(|s| s.parse().ok())
            .unwrap_or(8888)
    };
    let threads = dotenv::var("SERVER_THREADS")
        .map(|s| s.parse().expect("SERVER_THREADS was not a valid number"))
        .unwrap_or_else(|_| {
            if config.env == Env::Development {
                5
            } else {
                // A large default because this can be easily changed via env and in production we
                // want the logging middleware to accurately record the start time.
                500
            }
        });

    let server = if dotenv::var("WEB_USE_CIVET").is_err() {
        use tokio::io::AsyncWriteExt;
        use tokio::signal::unix::{signal, SignalKind};

        println!("Booting with a hyper based server");

        let mut rt = tokio::runtime::Builder::new()
            .threaded_scheduler()
            .enable_all()
            .core_threads(CORE_THREADS)
            .max_threads(threads as usize + CORE_THREADS)
            .build()
            .unwrap();

        let handler = Arc::new(conduit_hyper::BlockingHandler::new(app));
        let make_service =
            hyper::service::make_service_fn(move |socket: &hyper::server::conn::AddrStream| {
                let addr = socket.remote_addr();
                let handler = handler.clone();
                async move { Service::from_blocking(handler, addr) }
            });

        let addr = ([127, 0, 0, 1], port).into();
        #[allow(clippy::async_yields_async)]
        let server = rt.block_on(async { hyper::Server::bind(&addr).serve(make_service) });

        let mut sig_int = rt.block_on(async { signal(SignalKind::interrupt()) })?;
        let mut sig_term = rt.block_on(async { signal(SignalKind::terminate()) })?;

        let server = server.with_graceful_shutdown(async move {
            // Wait for either signal
            futures_util::select! {
                _ = sig_int.recv().fuse() => (),
                _ = sig_term.recv().fuse() => (),
            };
            let mut stdout = tokio::io::stdout();
            stdout.write_all(b"Starting graceful shutdown\n").await.ok();
        });

        let server = rt.spawn(async { server.await.unwrap() });
        Hyper(rt, server)
    } else {
        println!("Booting with a civet based server");
        let mut cfg = civet::Config::new();
        cfg.port(port).threads(threads).keep_alive(true);
        Civet(CivetServer::start(cfg, app).unwrap())
    };

    println!("listening on port {}", port);

    // Give tokio a chance to spawn the first worker thread
    thread::sleep(Duration::from_millis(10));

    // Creating this file tells heroku to tell nginx that the application is ready
    // to receive traffic.
    if heroku {
        let path = if fastboot {
            "/tmp/backend-initialized"
        } else {
            "/tmp/app-initialized"
        };
        println!("Writing to {}", path);
        File::create(path).unwrap();
    }

    // Block the main thread until the server has shutdown
    match server {
        Hyper(mut rt, server) => {
            rt.block_on(async { server.await.unwrap() });
        }
        Civet(server) => {
            let (tx, rx) = channel::<()>();
            ctrlc_handler(move || tx.send(()).unwrap_or(()));
            rx.recv().unwrap();
            drop(server);
        }
    }

    println!("Server has gracefully shutdown!");
    Ok(())
}

fn ctrlc_handler<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    let call_once = Mutex::new(Some(f));

    ctrlc::set_handler(move || {
        if let Some(f) = call_once.lock().unwrap().take() {
            println!("Starting graceful shutdown");
            f();
        } else {
            println!("Already sent signal to start graceful shutdown");
        }
    })
    .unwrap();
}
<|endoftext|>


<commit_before>use super::Blob;
use failure::Error;
use futures_util::{
    future::{FutureExt, TryFutureExt},
    stream::{FuturesUnordered, StreamExt},
};
use log::{error, warn};
use rusoto_core::region::Region;
use rusoto_credential::DefaultCredentialsProvider;
use rusoto_s3::{GetObjectRequest, PutObjectRequest, S3Client, S3};
use std::convert::TryInto;
use std::io::Read;
use time::Timespec;
use tokio::runtime::{Handle, Runtime};

#[cfg(test)]
mod test;
#[cfg(test)]
pub(crate) use test::TestS3;

pub(crate) static S3_BUCKET_NAME: &str = "rust-docs-rs";

pub(crate) struct S3Backend<'a> {
    client: S3Client,
    bucket: &'a str,
    runtime: Runtime,
}

impl<'a> S3Backend<'a> {
    pub(crate) fn new(client: S3Client, bucket: &'a str) -> Self {
        Self {
            client,
            bucket,
            runtime: Runtime::new().unwrap(),
        }
    }

    #[cfg(test)]
    pub(crate) fn with_runtime(client: S3Client, bucket: &'a str, runtime: Runtime) -> Self {
        Self {
            client,
            bucket,
            runtime,
        }
    }

    pub(super) fn get(&mut self, path: &str) -> Result<Blob, Error> {
        let res = self
            .runtime
            .block_on(self.client.get_object(GetObjectRequest {
                bucket: self.bucket.to_string(),
                key: path.into(),
                ..Default::default()
            }))?;

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::with_capacity(
            res.content_length
                .and_then(|l| l.try_into().ok())
                .unwrap_or(0),
        );
        b.read_to_end(&mut content).unwrap();

        let date_updated = parse_timespec(&res.last_modified.unwrap())?;

        Ok(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated,
            content,
        })
    }

    pub(super) fn store_batch(&mut self, mut uploads: Vec<Blob>) -> Result<(), Error> {
        let mut attempts = 0;

        loop {
            // `FuturesUnordered` is used because the order of execution doesn't
            // matter, we just want things to execute as fast as possible
            let futures = FuturesUnordered::new();

            // Drain uploads, filling `futures` with upload requests
            for blob in uploads.drain(..) {
                futures.push(
                    self.client
                        .put_object(PutObjectRequest {
                            bucket: self.bucket.to_string(),
                            key: blob.path.clone(),
                            body: Some(blob.content.clone().into()),
                            content_type: Some(blob.mime.clone()),
                            ..Default::default()
                        })
                        // Drop the value returned by `put_object` because we don't need it,
                        // emit an error and replace the error values with the blob that failed
                        // to upload so that we can retry failed uploads
                        .map(|resp| match resp {
                            Ok(..) => Ok(()),
                            Err(err) => {
                                error!("failed to upload file to s3: {:?}", err);
                                Err(blob)
                            }
                        })
                        .inspect_ok(|_| {
                            // Increment the total uploaded files when a file is uploaded
                            crate::web::metrics::UPLOADED_FILES_TOTAL.inc_by(1);
                        }),
                );
            }
            attempts += 1;

            // Collect all the failed uploads so that we can retry them
            uploads = self.runtime.block_on(
                futures
                    .filter_map(|resp| async move { resp.err() })
                    .collect(),
            );

            // If there are no further uploads we were successful and can return
            if uploads.is_empty() {
                break;

            // If more than three attempts to upload fail, return an error
            } else if attempts >= 3 {
                error!("failed to upload to s3, abandoning");
                failure::bail!("Failed to upload to s3 three times, abandoning");
            }
        }

        Ok(())
    }

    pub fn runtime_handle(&self) -> Handle {
        self.runtime.handle().clone()
    }

    pub fn client(&self) -> &S3Client {
        &self.client
    }
}

fn parse_timespec(raw: &str) -> Result<Timespec, Error> {
    const TIME_FMT: &str = "%a, %d %b %Y %H:%M:%S %Z";
    Ok(time::strptime(raw, TIME_FMT)?.to_timespec())
}

pub(crate) fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() && std::env::var_os("FORCE_S3").is_none() {
        return None;
    }

    let creds = match DefaultCredentialsProvider::new() {
        Ok(creds) => creds,
        Err(err) => {
            warn!("failed to retrieve AWS credentials: {}", err);
            return None;
        }
    };

    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        creds,
        std::env::var("S3_ENDPOINT")
            .ok()
            .map(|e| Region::Custom {
                name: std::env::var("S3_REGION").unwrap_or_else(|_| "us-west-1".to_owned()),
                endpoint: e,
            })
            .unwrap_or(Region::UsWest1),
    ))
}

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

    #[test]
    fn test_parse_timespec() {
        // Test valid conversions
        assert_eq!(
            parse_timespec("Thu, 1 Jan 1970 00:00:00 GMT").unwrap(),
            Timespec::new(0, 0)
        );
        assert_eq!(
            parse_timespec("Mon, 16 Apr 2018 04:33:50 GMT").unwrap(),
            Timespec::new(1523853230, 0)
        );

        // Test invalid conversion
        assert!(parse_timespec("foo").is_err());
    }

    #[test]
    fn test_get() {
        wrapper(|env| {
            let blob = Blob {
                path: "dir/foo.txt".into(),
                mime: "text/plain".into(),
                date_updated: Timespec::new(42, 0),
                content: "Hello world!".into(),
            };

            // Add a test file to the database
            let s3 = env.s3();
            s3.upload(vec![blob.clone()]).unwrap();

            // Test that the proper file was returned
            s3.assert_blob(&blob, "dir/foo.txt");

            // Test that other files are not returned
            s3.assert_404("dir/bar.txt");
            s3.assert_404("foo.txt");

            Ok(())
        });
    }

    #[test]
    fn test_store() {
        wrapper(|env| {
            let s3 = env.s3();
            let names = [
                "a",
                "b",
                "a_very_long_file_name_that_has_an.extension",
                "parent/child",
                "h/i/
                g/h/l/y/_/n/e/s/t/e/d/_/d/i/r/e/c/t/o/r/i/e/s",
            ];

            let blobs: Vec<_> = names
                .iter()
                .map(|&path| Blob {
                    path: path.into(),
                    mime: "text/plain".into(),
                    date_updated: Timespec::new(42, 0),
                    content: "Hello world!".into(),
                })
                .collect();

            s3.upload(blobs.clone()).unwrap();
            for blob in &blobs {
                s3.assert_blob(blob, &blob.path);
            }

            Ok(())
        })
    }
    // NOTE: trying to upload a file ending with `/` will behave differently in test and prod.
    // NOTE: On s3, it will succeed and create a file called `/`.
    // NOTE: On min.io, it will fail with 'Object name contains unsupported characters.'
}
<commit_msg>Moved unload increment<commit_after>use super::Blob;
use failure::Error;
use futures_util::{
    future::FutureExt,
    stream::{FuturesUnordered, StreamExt},
};
use log::{error, warn};
use rusoto_core::region::Region;
use rusoto_credential::DefaultCredentialsProvider;
use rusoto_s3::{GetObjectRequest, PutObjectRequest, S3Client, S3};
use std::convert::TryInto;
use std::io::Read;
use time::Timespec;
use tokio::runtime::{Handle, Runtime};

#[cfg(test)]
mod test;
#[cfg(test)]
pub(crate) use test::TestS3;

pub(crate) static S3_BUCKET_NAME: &str = "rust-docs-rs";

pub(crate) struct S3Backend<'a> {
    client: S3Client,
    bucket: &'a str,
    runtime: Runtime,
}

impl<'a> S3Backend<'a> {
    pub(crate) fn new(client: S3Client, bucket: &'a str) -> Self {
        Self {
            client,
            bucket,
            runtime: Runtime::new().unwrap(),
        }
    }

    #[cfg(test)]
    pub(crate) fn with_runtime(client: S3Client, bucket: &'a str, runtime: Runtime) -> Self {
        Self {
            client,
            bucket,
            runtime,
        }
    }

    pub(super) fn get(&mut self, path: &str) -> Result<Blob, Error> {
        let res = self
            .runtime
            .block_on(self.client.get_object(GetObjectRequest {
                bucket: self.bucket.to_string(),
                key: path.into(),
                ..Default::default()
            }))?;

        let mut b = res.body.unwrap().into_blocking_read();
        let mut content = Vec::with_capacity(
            res.content_length
                .and_then(|l| l.try_into().ok())
                .unwrap_or(0),
        );
        b.read_to_end(&mut content).unwrap();

        let date_updated = parse_timespec(&res.last_modified.unwrap())?;

        Ok(Blob {
            path: path.into(),
            mime: res.content_type.unwrap(),
            date_updated,
            content,
        })
    }

    pub(super) fn store_batch(&mut self, mut uploads: Vec<Blob>) -> Result<(), Error> {
        let mut attempts = 0;

        loop {
            // `FuturesUnordered` is used because the order of execution doesn't
            // matter, we just want things to execute as fast as possible
            let futures = FuturesUnordered::new();

            // Drain uploads, filling `futures` with upload requests
            for blob in uploads.drain(..) {
                futures.push(
                    self.client
                        .put_object(PutObjectRequest {
                            bucket: self.bucket.to_string(),
                            key: blob.path.clone(),
                            body: Some(blob.content.clone().into()),
                            content_type: Some(blob.mime.clone()),
                            ..Default::default()
                        })
                        // Drop the value returned by `put_object` because we don't need it,
                        // emit an error and replace the error values with the blob that failed
                        // to upload so that we can retry failed uploads
                        .map(|resp| match resp {
                            Ok(..) => {
                                // Increment the total uploaded files when a file is uploaded
                                crate::web::metrics::UPLOADED_FILES_TOTAL.inc_by(1);

                                Ok(())
                            }
                            Err(err) => {
                                error!("failed to upload file to s3: {:?}", err);
                                Err(blob)
                            }
                        }),
                );
            }
            attempts += 1;

            // Collect all the failed uploads so that we can retry them
            uploads = self.runtime.block_on(
                futures
                    .filter_map(|resp| async move { resp.err() })
                    .collect(),
            );

            // If there are no further uploads we were successful and can return
            if uploads.is_empty() {
                break;

            // If more than three attempts to upload fail, return an error
            } else if attempts >= 3 {
                error!("failed to upload to s3, abandoning");
                failure::bail!("Failed to upload to s3 three times, abandoning");
            }
        }

        Ok(())
    }

    pub fn runtime_handle(&self) -> Handle {
        self.runtime.handle().clone()
    }

    pub fn client(&self) -> &S3Client {
        &self.client
    }
}

fn parse_timespec(raw: &str) -> Result<Timespec, Error> {
    const TIME_FMT: &str = "%a, %d %b %Y %H:%M:%S %Z";
    Ok(time::strptime(raw, TIME_FMT)?.to_timespec())
}

pub(crate) fn s3_client() -> Option<S3Client> {
    // If AWS keys aren't configured, then presume we should use the DB exclusively
    // for file storage.
    if std::env::var_os("AWS_ACCESS_KEY_ID").is_none() && std::env::var_os("FORCE_S3").is_none() {
        return None;
    }

    let creds = match DefaultCredentialsProvider::new() {
        Ok(creds) => creds,
        Err(err) => {
            warn!("failed to retrieve AWS credentials: {}", err);
            return None;
        }
    };

    Some(S3Client::new_with(
        rusoto_core::request::HttpClient::new().unwrap(),
        creds,
        std::env::var("S3_ENDPOINT")
            .ok()
            .map(|e| Region::Custom {
                name: std::env::var("S3_REGION").unwrap_or_else(|_| "us-west-1".to_owned()),
                endpoint: e,
            })
            .unwrap_or(Region::UsWest1),
    ))
}

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

    #[test]
    fn test_parse_timespec() {
        // Test valid conversions
        assert_eq!(
            parse_timespec("Thu, 1 Jan 1970 00:00:00 GMT").unwrap(),
            Timespec::new(0, 0)
        );
        assert_eq!(
            parse_timespec("Mon, 16 Apr 2018 04:33:50 GMT").unwrap(),
            Timespec::new(1523853230, 0)
        );

        // Test invalid conversion
        assert!(parse_timespec("foo").is_err());
    }

    #[test]
    fn test_get() {
        wrapper(|env| {
            let blob = Blob {
                path: "dir/foo.txt".into(),
                mime: "text/plain".into(),
                date_updated: Timespec::new(42, 0),
                content: "Hello world!".into(),
            };

            // Add a test file to the database
            let s3 = env.s3();
            s3.upload(vec![blob.clone()]).unwrap();

            // Test that the proper file was returned
            s3.assert_blob(&blob, "dir/foo.txt");

            // Test that other files are not returned
            s3.assert_404("dir/bar.txt");
            s3.assert_404("foo.txt");

            Ok(())
        });
    }

    #[test]
    fn test_store() {
        wrapper(|env| {
            let s3 = env.s3();
            let names = [
                "a",
                "b",
                "a_very_long_file_name_that_has_an.extension",
                "parent/child",
                "h/i/
                g/h/l/y/_/n/e/s/t/e/d/_/d/i/r/e/c/t/o/r/i/e/s",
            ];

            let blobs: Vec<_> = names
                .iter()
                .map(|&path| Blob {
                    path: path.into(),
                    mime: "text/plain".into(),
                    date_updated: Timespec::new(42, 0),
                    content: "Hello world!".into(),
                })
                .collect();

            s3.upload(blobs.clone()).unwrap();
            for blob in &blobs {
                s3.assert_blob(blob, &blob.path);
            }

            Ok(())
        })
    }
    // NOTE: trying to upload a file ending with `/` will behave differently in test and prod.
    // NOTE: On s3, it will succeed and create a file called `/`.
    // NOTE: On min.io, it will fail with 'Object name contains unsupported characters.'
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use std::mem::replace;

use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> : Debug+Hash+PartialEq+Eq+Clone {
    type List : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Box<Self::List>) -> Self::List ;
    fn rc   (&mut A, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::List>) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (self:&Self, &mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res ;

    // Derived from `elim` above:
    fn is_empty (self:&Self, st:&mut A, list:&Self::List) -> bool {
        self.elim(st, &list, |_|true, |_,_,_|false, |_,_,_|false)
    }
}

// Questions:
//  - Should `Name`s always be passed by reference?
//  - Do these Fn argss for fold need to be passed in `Rc<Box<_>>`s ?

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> : Debug+Hash+PartialEq+Eq+Clone {
    type Tree : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Box<Self::Tree>, Box<Self::Tree>) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::Tree>, Box<Self::Tree>) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC> (&mut A, Self::Tree, Res, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Res, Leaf) -> Res
        ,      BinC:Fn(&mut A, Res, Bin ) -> Res ;

    fn fold_up<Arg,Res,LeafC,BinC> (&mut A, Self::Tree, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Leaf) -> Res
        ,      BinC:Fn(&mut A, Bin, Res, Res ) -> Res ;

    // TODO: Add derived operations (max, min, sum, etc.) for fold_up.
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,      Box<List<A,Hd>>),
    Rc(           Rc<List<A,Hd>>),
    Name(A::Name, Box<List<A,Hd>>),
    Art(          Art<List<A,Hd>, A::Loc>),
}

// TODO: Why Does Adapton have to implement all of these?
//       It's not actually *contained* within the List structure; it cannot be ecountered there.
//       It's only ever present in a negative position (as a function parameter).
impl<A:Adapton+Debug+Hash+PartialEq+Eq+Clone,Hd:Debug+Hash+PartialEq+Eq+Clone> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                                  -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Box<Self::List>)       -> Self::List { List::Cons(hd,tl) }
    fn name (_:&mut A, nm:A::Name, tl:Box<Self::List>)  -> Self::List { List::Name(nm, tl) }
    fn rc   (_:&mut A, rc:Rc<List<A,Hd>>)               -> Self::List { List::Rc(rc) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>)      -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (self:&Self, st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, tl),
            List::Name(ref nm, ref tl) => namef(st, nm, tl),
            List::Rc(ref rc) => self.elim(st, &*rc, nilf, consf, namef),
            List::Art(ref art) => {
                let list = st.force(art);
                self.elim(st, &list, nilf, consf, namef)
            }
        }
    }
}

// https://doc.rust-lang.org/book/macros.html
//
// macro_rules! o_O {
//     (
//         $(
//             $x:expr; [ $( $y:expr ),* ]
//          );*
//     ) => {
//         &[ $($( $x + $y ),*),* ]
//     }
// }
//
// fn main() {
//     let a: &[i32]
//         = o_O!(10; [1, 2, 3];
//                20; [4, 5, 6]);
//
//     assert_eq!(a, [11, 12, 13, 24, 25, 26]);
// }

// TODO: Need to gensym a variable for each argument below:
//
// macro_rules! thunk {
//     ( $f:ident , $st:expr , $( $arg:expr ),* ) => {
//         let fval = Rc::new(Box::new(
//             |st, args|{
//                 let $( $arg ),* = args ;
//                 f(st, l, list, left_tree, left_tree_lev, parent_lev)
//             })) ;
//         ($st).thunk (ArtId::Eager, prog_pt!(f), fval, $( $arg ),* )
//     }}

fn tree_of_list_rec_memo <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32) ->
    (T::Tree, L::List)
{
    let t = st.thunk (ArtId::Eager,
                      prog_pt!(tree_of_list_rec),
                      Rc::new(Box::new(|st, args|{
                          let (l, list, left_tree, left_tree_lev, parent_lev) = args ;
                          tree_of_list_rec::<A,X,T,L>
                              (st, l, list, left_tree, left_tree_lev, parent_lev)
                      })),
                      (l, list, left_tree, left_tree_lev, parent_lev)
                      ) ;
    st.force( &t )
}

fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32)
     -> (T::Tree, L::List)
{
    l.elim (
        st, &list,
        /* Nil */  |st| ( T::nil(st), L::nil(st) ),
        /* Cons */ |st, hd, rest| {
            let lev_hd = (1 + (my_hash(hd).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_hd && lev_hd <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, l, rest, &nil, 0 as u32, lev_hd ) ;
                let tree = T::bin ( st, hd.clone(), Box::new(left_tree.clone()), Box::new(right_tree) ) ;
                tree_of_list_rec::<A,X,T,L> ( st, l, &rest, &tree, lev_hd, parent_lev )
            }
            else {
                let rest = L::cons(st, hd.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }},
        /* Name */ |st, nm, rest| {
            let lev_nm = (1 + 64 + (my_hash(nm).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_nm && lev_nm <= parent_lev {
                let nil = T::nil(st) ;
                // Done: Memoized the recursive calls to tree_of_list_rec.
                let (right_tree, rest) = tree_of_list_rec_memo::<A,X,T,L> ( st, l, rest, &nil, 0 as u32, lev_nm ) ;
                // TODO: Place left_ and right_ trees into articulations (not Boxes), named by name.
                let tree = T::name( st, nm.clone(), Box::new(left_tree.clone()), Box::new(right_tree) ) ;
                tree_of_list_rec_memo::<A,X,T,L> ( st, l, &rest, &tree, lev_nm, parent_lev )
            }
            else {
                let rest = L::name(st, nm.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }}
        )
}

pub fn tree_of_list <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (l:&L, st:&mut A, list:&L::List) -> T::Tree
{
    let nil = T::nil(st) ;
    let (tree, rest) = tree_of_list_rec::<A,X,T,L> (st, l, list, &nil, 0 as u32, u32::max_value()) ;
    assert!( l.is_empty( st, &rest ) );
    tree
}
<commit_msg>stuck, due to rustc not understanding that elim is a pattern-match; its arms are mutually-exclusive<commit_after>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use std::mem::replace;

use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> : Debug+Hash+PartialEq+Eq+Clone {
    type List : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Box<Self::List>) -> Self::List ;
    fn rc   (&mut A, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::List>) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (self:&Self, &mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res ;

    // Derived from `elim` above:
    fn is_empty (self:&Self, st:&mut A, list:&Self::List) -> bool {
        self.elim(st, &list, |_|true, |_,_,_|false, |_,_,_|false)
    }
}

// Questions:
//  - Should `Name`s always be passed by reference?
//  - Do these Fn argss for fold need to be passed in `Rc<Box<_>>`s ?

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> : Debug+Hash+PartialEq+Eq+Clone {
    type Tree : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Self::Tree, Self::Tree) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Self::Tree, Self::Tree) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC> (&mut A, Self::Tree, Res, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Res, Leaf) -> Res
        ,      BinC:Fn(&mut A, Res, Bin ) -> Res ;

    fn fold_up<Arg,Res,LeafC,BinC> (&mut A, Self::Tree, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Leaf) -> Res
        ,      BinC:Fn(&mut A, Bin, Res, Res ) -> Res ;

    // TODO: Add derived operations (max, min, sum, etc.) for fold_up.
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,      Box<List<A,Hd>>),
    Rc(           Rc<List<A,Hd>>),
    Name(A::Name, Box<List<A,Hd>>),
    Art(          Art<List<A,Hd>, A::Loc>),
}

// TODO: Why Does Adapton have to implement all of these?
//       It's not actually *contained* within the List structure; it cannot be ecountered there.
//       It's only ever present in a negative position (as a function parameter).
impl<A:Adapton+Debug+Hash+PartialEq+Eq+Clone,Hd:Debug+Hash+PartialEq+Eq+Clone> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                                  -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Box<Self::List>)       -> Self::List { List::Cons(hd,tl) }
    fn name (_:&mut A, nm:A::Name, tl:Box<Self::List>)  -> Self::List { List::Name(nm, tl) }
    fn rc   (_:&mut A, rc:Rc<List<A,Hd>>)               -> Self::List { List::Rc(rc) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>)      -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (self:&Self, st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, tl),
            List::Name(ref nm, ref tl) => namef(st, nm, tl),
            List::Rc(ref rc) => self.elim(st, &*rc, nilf, consf, namef),
            List::Art(ref art) => {
                let list = st.force(art);
                self.elim(st, &list, nilf, consf, namef)
            }
        }
    }
}

// https://doc.rust-lang.org/book/macros.html
//
// macro_rules! o_O {
//     (
//         $(
//             $x:expr; [ $( $y:expr ),* ]
//          );*
//     ) => {
//         &[ $($( $x + $y ),*),* ]
//     }
// }
//
// fn main() {
//     let a: &[i32]
//         = o_O!(10; [1, 2, 3];
//                20; [4, 5, 6]);
//
//     assert_eq!(a, [11, 12, 13, 24, 25, 26]);
// }

// TODO: Need to gensym a variable for each argument below:
//
// macro_rules! thunk {
//     ( $f:ident , $st:expr , $( $arg:expr ),* ) => {
//         let fval = Rc::new(Box::new(
//             |st, args|{
//                 let $( $arg ),* = args ;
//                 f(st, l, list, left_tree, left_tree_lev, parent_lev)
//             })) ;
//         ($st).thunk (ArtId::Eager, prog_pt!(f), fval, $( $arg ),* )
//     }}

fn tree_of_list_rec_memo <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:T::Tree, left_tree_lev:u32, parent_lev:u32) ->
    (T::Tree, L::List)
{
    let t = st.thunk (ArtId::Eager,
                      prog_pt!(tree_of_list_rec),
                      Rc::new(Box::new(|st, args|{
                          let (l, list, left_tree, left_tree_lev, parent_lev) = args ;
                          tree_of_list_rec::<A,X,T,L>
                              (st, l, list, left_tree, left_tree_lev, parent_lev)
                      })),
                      (l, list, left_tree, left_tree_lev, parent_lev)
                      ) ;
    st.force( &t )
}

fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:T::Tree, left_tree_lev:u32, parent_lev:u32)
     -> (T::Tree, L::List)
{
    l.elim (
        st, &list,
        /* Nil */  |st| ( T::nil(st), L::nil(st) ),
        /* Cons */ |st, hd, rest| {
            let lev_hd = (1 + (my_hash(hd).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_hd && lev_hd <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, l, rest, nil, 0 as u32, lev_hd ) ;
                let tree = T::bin ( st, hd.clone(), left_tree, right_tree ) ;
                tree_of_list_rec::<A,X,T,L> ( st, l, &rest, tree, lev_hd, parent_lev )
            }
            else {
                let rest = L::cons(st, hd.clone(), rest.clone()) ;
                (left_tree, rest)
            }},
        /* Name */ |st, nm, rest| {
            let lev_nm = (1 + 64 + (my_hash(nm).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_nm && lev_nm <= parent_lev {
                let nil = T::nil(st) ;
                // Done: Memoized the recursive calls to tree_of_list_rec.
                let (right_tree, rest) = tree_of_list_rec_memo::<A,X,T,L> ( st, l, rest, nil, 0 as u32, lev_nm ) ;
                // TODO: Place left_ and right_ trees into articulations (not Boxes), named by name.
                let tree = T::name( st, nm.clone(), left_tree, right_tree ) ;
                tree_of_list_rec_memo::<A,X,T,L> ( st, l, &rest, tree, lev_nm, parent_lev )
            }
            else {
                let rest = L::name(st, nm.clone(), rest.clone()) ;
                (left_tree, rest)
            }}
        )
}

pub fn tree_of_list <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (l:&L, st:&mut A, list:&L::List) -> T::Tree
{
    let nil = T::nil(st) ;
    let (tree, rest) = tree_of_list_rec::<A,X,T,L> (st, l, list, nil, 0 as u32, u32::max_value()) ;
    assert!( l.is_empty( st, &rest ) );
    tree
}
<|endoftext|>


<commit_before>use std::io;
use std::time::Duration;
use std::sync::Arc;

use futures::{Future, future};
use futures_cpupool::CpuPool;
use num_cpus;

use tokio_service::Service;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use tcp::shortcut;
use bifrost_hasher::hash_str;
use super::STANDALONE_ADDRESS;
use DISABLE_SHORTCUT;

pub type ResFuture = Future<Item = Vec<u8>, Error = io::Error>;

lazy_static! {
    pub static ref CONNECTING_POOL: CpuPool = CpuPool::new(10 * num_cpus::get());
}

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<Timeout<ClientCore>>,
    pub server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        Box::new(self.inner.call(req))
    }
}

impl Client {
    pub fn connect_with_timeout (address: &String, timeout: Duration) -> io::Result<Client> {
        let server_id = hash_str(address);
        let client = {
            if !DISABLE_SHORTCUT && shortcut::is_local(server_id) {
                None
            } else {
                if address.eq(&STANDALONE_ADDRESS) {
                    return Err(io::Error::new(io::ErrorKind::Other, "STANDALONE server is not found"))
                }
                let mut core = Core::new()?;
                let socket_address = address.parse().unwrap();
                let future = Box::new(TcpClient::new(BytesClientProto)
                    .connect(&socket_address, &core.handle())
                    .map(|c| Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout)));
                Some(core.run(future)?)
            }
        };
        Ok(Client {
            client,
            server_id,
        })
    }
    pub fn connect (address: &String) -> io::Result<Client> {
        Client::connect_with_timeout(address, Duration::from_secs(5))
    }
    pub fn connect_with_timeout_async (address: String, timeout: Duration)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move ||{
            Client::connect_with_timeout(&address, timeout)
        })
    }
    pub fn connect_async (address: String)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move || {
            Client::connect_with_timeout(&address, Duration::from_secs(5))
        })
    }
    pub fn send(&self, msg: Vec<u8>) -> io::Result<Vec<u8>> {
        self.send_async(msg).wait()
    }
    pub fn send_async(&self, msg: Vec<u8>) -> Box<ResFuture> {
        if let Some(ref client) = self.client {
            box client.call(msg)
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<commit_msg>comment on initalizing client<commit_after>use std::io;
use std::time::Duration;
use std::sync::Arc;

use futures::{Future, future};
use futures_cpupool::CpuPool;
use num_cpus;

use tokio_service::Service;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use tcp::shortcut;
use bifrost_hasher::hash_str;
use super::STANDALONE_ADDRESS;
use DISABLE_SHORTCUT;

pub type ResFuture = Future<Item = Vec<u8>, Error = io::Error>;

lazy_static! {
    pub static ref CONNECTING_POOL: CpuPool = CpuPool::new(10 * num_cpus::get());
}

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<Timeout<ClientCore>>,
    pub server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        Box::new(self.inner.call(req))
    }
}

impl Client {
    pub fn connect_with_timeout (address: &String, timeout: Duration) -> io::Result<Client> {
        let server_id = hash_str(address);
        let client = {
            if !DISABLE_SHORTCUT && shortcut::is_local(server_id) {
                None
            } else {
                if address.eq(&STANDALONE_ADDRESS) {
                    return Err(io::Error::new(io::ErrorKind::Other, "STANDALONE server is not found"))
                }
                let mut core = Core::new()?;
                let socket_address = address.parse().unwrap();
                let future = Box::new(TcpClient::new(BytesClientProto)
                    .connect(&socket_address, &core.handle())
                    .map(|c| Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout)));
                Some(core.run(future)?) // this is required, or client won't receive response
            }
        };
        Ok(Client {
            client,
            server_id,
        })
    }
    pub fn connect (address: &String) -> io::Result<Client> {
        Client::connect_with_timeout(address, Duration::from_secs(5))
    }
    pub fn connect_with_timeout_async (address: String, timeout: Duration)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move ||{
            Client::connect_with_timeout(&address, timeout)
        })
    }
    pub fn connect_async (address: String)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move || {
            Client::connect_with_timeout(&address, Duration::from_secs(5))
        })
    }
    pub fn send(&self, msg: Vec<u8>) -> io::Result<Vec<u8>> {
        self.send_async(msg).wait()
    }
    pub fn send_async(&self, msg: Vec<u8>) -> Box<ResFuture> {
        if let Some(ref client) = self.client {
            box client.call(msg)
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<|endoftext|>


<commit_before>use std::io;
use std::net::SocketAddr;
use std::time::Duration;

use futures::{self, BoxFuture, Future};

use tokio_service::Service;
use tokio_core::io::Io;
use tokio_core::reactor::Handle;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientProto, ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use bifrost_hasher::hash_str;
use shortcut::{tcp as shortcut};

pub type ResFuture = Future<Item = Vec<u8>, Error = io::Error>;

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<Timeout<ClientCore>>,
    server_id: u64,
    core: Box<Core>,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        self.inner.call(req).boxed()
    }
}

impl Client {
    pub fn connect_with_timeout (address: &String, timeout: Duration) -> io::Result<Client> {
        let mut core = Core::new()?;
        let server_id = hash_str(address);
        let client = {
            if shortcut::is_local(server_id) {
                None
            } else {
                let socket_address = address.parse().unwrap();
                let future = Box::new(TcpClient::new(BytesClientProto)
                    .connect(&socket_address, &core.handle())
                    .map(|c| Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout)));
                Some(core.run(future)?)
            }
        };
        Ok(Client {
            client: client,
            core: Box::new(core),
            server_id: server_id,
        })
    }
    pub fn connect (address: &String) -> io::Result<Client> {
        Client::connect_with_timeout(address, Duration::from_secs(5))
    }
    pub fn send(&mut self, msg: Vec<u8>) -> io::Result<Vec<u8>> {
        let future = self.send_async(msg);
        if let Some(ref client) = self.client {
            self.core.run(future)
        } else {
            future.wait()
        }
    }
    pub fn send_async(&mut self, msg: Vec<u8>) -> Box<ResFuture> {
        if let Some(ref client) = self.client {
            Box::new(client.call(msg))
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<commit_msg>use event loop only if it have to<commit_after>use std::io;
use std::net::SocketAddr;
use std::time::Duration;

use futures::{self, BoxFuture, Future};

use tokio_service::Service;
use tokio_core::io::Io;
use tokio_core::reactor::Handle;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientProto, ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use bifrost_hasher::hash_str;
use shortcut::{tcp as shortcut};

pub type ResFuture = Future<Item = Vec<u8>, Error = io::Error>;

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<(Timeout<ClientCore>, Core)>,
    server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        self.inner.call(req).boxed()
    }
}

impl Client {
    pub fn connect_with_timeout (address: &String, timeout: Duration) -> io::Result<Client> {
        let server_id = hash_str(address);
        let client = {
            let mut core = Core::new()?;
            if shortcut::is_local(server_id) {
                None
            } else {
                let socket_address = address.parse().unwrap();
                let future = Box::new(TcpClient::new(BytesClientProto)
                    .connect(&socket_address, &core.handle())
                    .map(|c| Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout)));
                Some((core.run(future)?, core))
            }
        };
        Ok(Client {
            client: client,
            server_id: server_id,
        })
    }
    pub fn connect (address: &String) -> io::Result<Client> {
        Client::connect_with_timeout(address, Duration::from_secs(5))
    }
    pub fn send(&mut self, msg: Vec<u8>) -> io::Result<Vec<u8>> {
        let future = self.send_async(msg);
        if let Some((ref client, ref mut core)) = self.client {
            core.run(future)
        } else {
            future.wait()
        }
    }
    pub fn send_async(&mut self, msg: Vec<u8>) -> Box<ResFuture> {
        if let Some((ref client, _)) = self.client {
            Box::new(client.call(msg))
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<|endoftext|>


<commit_before>//! Dedicated single thread actor-ref implementations

use std::thread;
use std::sync::mpsc::{channel, Sender};
use std::sync::mpsc;

use std::sync::{Arc, Mutex};
use std::convert::From;

use {Actor, ActorSpawner};
use ActorRef;
use {SendError, SendErrorReason};

#[cfg(test)]
mod tests;

enum ActorCellMessage<Message> {
	Process(Message),
	StopAndNotify
}

/// A simplistic environment to run an actor in
/// which can act as ActorRef.
///
/// Currently, it still uses one thread per actor.
struct ActorCell<Message, A: Actor<Message>> {
	// TODO: clone sender instead of mutex
	tx: Mutex<Sender<ActorCellMessage<Message>>>,
	actor: Mutex<Option<A>>
}

impl<Message, A: Actor<Message>> Drop for ActorCell<Message, A> {
	fn drop(&mut self) {
		// FIXME: Is it clever that we might panic in Drop?
		self.tx.lock().unwrap().send(ActorCellMessage::StopAndNotify).unwrap();
	}
}

/// An ActorSpawner which spawns a dedicated thread for every
/// actor.
pub struct DedicatedThreadSpawner;

impl ActorSpawner for DedicatedThreadSpawner {
	/// Create and ActorCell for the given actor.
	fn spawn<Message, A>(&self, actor: A) -> Arc<ActorRef<Message>>
		where Message: Send + 'static, A: Actor<Message> + 'static
	{
		let (tx, rx) = channel();

		let actor_lock = Mutex::new(Some(actor));

		let ret_cell = Arc::new(ActorCell {
			tx: Mutex::new(tx),
			actor: actor_lock
		});

		let cell = ret_cell.clone();

		thread::spawn( move|| {
			let mut actor = cell.actor.lock().unwrap().take().unwrap();

			loop {
				match rx.recv().unwrap() {
					ActorCellMessage::Process(msg) => {
						actor.process(msg);
					},
					ActorCellMessage::StopAndNotify => {
						break;
					},
				}
			}
		});

		ret_cell
	}
}

impl<Message> From<mpsc::SendError<Message>> for SendError<Message> {
	fn from(err: mpsc::SendError<Message>) -> SendError<Message> {
		match err {
			mpsc::SendError(message) => SendError(SendErrorReason::Unreachable, message)
		}
	}
}

impl<Message: Send + 'static, A: 'static + Actor<Message>> ActorRef<Message> for ActorCell<Message, A> {
	fn send(&self, msg: Message) -> Result<(), SendError<Message>> {
		match self.tx.lock() {
			Err(..) =>
				Err(SendError(SendErrorReason::Unreachable, msg)),
			Ok(tx) =>
				tx.send(ActorCellMessage::Process(msg)).map_err({|err|
					match err {
						mpsc::SendError(ActorCellMessage::Process(msg)) =>
							SendError(SendErrorReason::Unreachable, msg),
						_ => unreachable!()
					}
				}),
		}
	}
}
<commit_msg>Require that messages are send<commit_after>//! Dedicated single thread actor-ref implementations

use std::thread;
use std::sync::mpsc::{channel, Sender};
use std::sync::mpsc;

use std::sync::{Arc, Mutex};
use std::convert::From;

use {Actor, ActorSpawner};
use ActorRef;
use {SendError, SendErrorReason};

#[cfg(test)]
mod tests;

enum ActorCellMessage<Message> where Message: Send {
	Process(Message),
	StopAndNotify
}

/// A simplistic environment to run an actor in
/// which can act as ActorRef.
///
/// Currently, it still uses one thread per actor.
struct ActorCell<Message, A: Actor<Message>> where Message: Send {
	// TODO: clone sender instead of mutex
	tx: Mutex<Sender<ActorCellMessage<Message>>>,
	actor: Mutex<Option<A>>
}

impl<Message, A: Actor<Message>> Drop for ActorCell<Message, A> where Message: Send {
	fn drop(&mut self) {
		// FIXME: Is it clever that we might panic in Drop?
		self.tx.lock().unwrap().send(ActorCellMessage::StopAndNotify).unwrap();
	}
}

/// An ActorSpawner which spawns a dedicated thread for every
/// actor.
pub struct DedicatedThreadSpawner;

impl ActorSpawner for DedicatedThreadSpawner {
	/// Create and ActorCell for the given actor.
	fn spawn<Message, A>(&self, actor: A) -> Arc<ActorRef<Message>>
		where Message: Send + 'static, A: Actor<Message> + 'static
	{
		let (tx, rx) = channel();

		let actor_lock = Mutex::new(Some(actor));

		let ret_cell = Arc::new(ActorCell {
			tx: Mutex::new(tx),
			actor: actor_lock
		});

		let cell = ret_cell.clone();

		thread::spawn( move|| {
			let mut actor = cell.actor.lock().unwrap().take().unwrap();

			loop {
				match rx.recv().unwrap() {
					ActorCellMessage::Process(msg) => {
						actor.process(msg);
					},
					ActorCellMessage::StopAndNotify => {
						break;
					},
				}
			}
		});

		ret_cell
	}
}

impl<Message> From<mpsc::SendError<Message>> for SendError<Message> {
	fn from(err: mpsc::SendError<Message>) -> SendError<Message> {
		match err {
			mpsc::SendError(message) => SendError(SendErrorReason::Unreachable, message)
		}
	}
}

impl<Message: Send + 'static, A: 'static + Actor<Message>> ActorRef<Message> for ActorCell<Message, A> {
	fn send(&self, msg: Message) -> Result<(), SendError<Message>> {
		match self.tx.lock() {
			Err(..) =>
				Err(SendError(SendErrorReason::Unreachable, msg)),
			Ok(tx) =>
				tx.send(ActorCellMessage::Process(msg)).map_err({|err|
					match err {
						mpsc::SendError(ActorCellMessage::Process(msg)) =>
							SendError(SendErrorReason::Unreachable, msg),
						_ => unreachable!()
					}
				}),
		}
	}
}
<|endoftext|>


<commit_before>
use ndarray::{Ix2, Array};

use matrix::{Matrix, MFloat};
use square::SquareMatrix;
use error::LinalgError;
use solve::ImplSolve;

pub trait TriangularMatrix: Matrix + SquareMatrix {
    /// solve a triangular system with upper triangular matrix
    fn solve_upper(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
    /// solve a triangular system with lower triangular matrix
    fn solve_lower(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
}

impl<A: MFloat> TriangularMatrix for Array<A, Ix2> {
    fn solve_upper(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'U' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
    fn solve_lower(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'L' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
}

pub fn drop_upper(mut a: Array<f64, Ix2>) -> Array<f64, Ix2> {
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = 0.0;
        }
    }
    a
}

pub fn drop_lower(mut a: Array<f64, Ix2>) -> Array<f64, Ix2> {
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = 0.0;
        }
    }
    a
}
<commit_msg>Rewrite drop_{upper,lower} for ArrayBase<S, Ix2><commit_after>
use ndarray::{Ix2, Array, NdFloat, ArrayBase, DataMut};

use matrix::{Matrix, MFloat};
use square::SquareMatrix;
use error::LinalgError;
use solve::ImplSolve;

pub trait TriangularMatrix: Matrix + SquareMatrix {
    /// solve a triangular system with upper triangular matrix
    fn solve_upper(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
    /// solve a triangular system with lower triangular matrix
    fn solve_lower(&self, Self::Vector) -> Result<Self::Vector, LinalgError>;
}

impl<A: MFloat> TriangularMatrix for Array<A, Ix2> {
    fn solve_upper(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'U' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
    fn solve_lower(&self, b: Self::Vector) -> Result<Self::Vector, LinalgError> {
        self.check_square()?;
        let (n, _) = self.size();
        let layout = self.layout()?;
        let a = self.as_slice_memory_order().unwrap();
        let x = ImplSolve::solve_triangle(layout, 'L' as u8, n, a, b.into_raw_vec())?;
        Ok(Array::from_vec(x))
    }
}

pub fn drop_upper<A: NdFloat, S>(mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where S: DataMut<Elem = A>
{
    for ((i, j), val) in a.indexed_iter_mut() {
        if i < j {
            *val = A::zero();
        }
    }
    a
}

pub fn drop_lower<A: NdFloat, S>(mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where S: DataMut<Elem = A>
{
    for ((i, j), val) in a.indexed_iter_mut() {
        if i > j {
            *val = A::zero();
        }
    }
    a
}
<|endoftext|>


<commit_before>// First a module with inner documentation

// @has issue_55364/subone/index.html
// These foo/bar links in the module's documentation should refer inside `subone`
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
pub mod subone {
    //! See either [foo] or [bar].

    // This should refer to subone's `bar`
    // @has issue_55364/subone/fn.foo.html
    // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
    /// See [bar]
    pub fn foo() {}
    // This should refer to subone's `foo`
    // @has issue_55364/subone/fn.bar.html
    // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
    /// See [foo]
    pub fn bar() {}
}

// A module with outer documentation

// @has issue_55364/subtwo/index.html
// These foo/bar links in the module's documentation should not reference inside `subtwo`
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
// Instead it should be referencing the top level functions
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
// Though there should be such links later
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.bar.html"]' 'bar'
/// See either [foo] or [bar].
pub mod subtwo {

    // Despite the module's docs referring to the top level foo/bar,
    // this should refer to subtwo's `bar`
    // @has issue_55364/subtwo/fn.foo.html
    // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
    /// See [bar]
    pub fn foo() {}
    // Despite the module's docs referring to the top level foo/bar,
    // this should refer to subtwo's `foo`
    // @has issue_55364/subtwo/fn.bar.html
    // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
    /// See [foo]
    pub fn bar() {}
}

// These are the function referred to by the module above with outer docs

/// See [bar]
pub fn foo() {}
/// See [foo]
pub fn bar() {}

// This module refers to the outer foo/bar by means of `super::`

// @has issue_55364/subthree/index.html
// This module should also refer to the top level foo/bar
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
pub mod subthree {
    //! See either [foo][super::foo] or [bar][super::bar]
}

// Next we go *deeper* - In order to ensure it's not just "this or parent"
// we test `crate::` and a `super::super::...` chain
// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
pub mod subfour {
    pub mod subfive {
        pub mod subsix {
            pub mod subseven {
                pub mod subeight {
                    /// See [other foo][crate::subone::foo]
                    pub fn foo() {}
                    /// See [other bar][super::super::super::super::super::subtwo::bar]
                    pub fn bar() {}
                }
            }
        }
    }
}
<commit_msg>Update rustdoc test<commit_after>// First a module with inner documentation

// @has issue_55364/subone/index.html
// These foo/bar links in the module's documentation should refer inside `subone`
// @has - '//section[@id="main"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
pub mod subone {
    //! See either [foo] or [bar].

    // This should refer to subone's `bar`
    // @has issue_55364/subone/fn.foo.html
    // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
    /// See [bar]
    pub fn foo() {}
    // This should refer to subone's `foo`
    // @has issue_55364/subone/fn.bar.html
    // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
    /// See [foo]
    pub fn bar() {}
}

// A module with outer documentation

// @has issue_55364/subtwo/index.html
// These foo/bar links in the module's documentation should not reference inside `subtwo`
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
// Instead it should be referencing the top level functions
// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
// Though there should be such links later
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.bar.html"]' 'bar'
/// See either [foo] or [bar].
pub mod subtwo {

    // Despite the module's docs referring to the top level foo/bar,
    // this should refer to subtwo's `bar`
    // @has issue_55364/subtwo/fn.foo.html
    // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
    /// See [bar]
    pub fn foo() {}
    // Despite the module's docs referring to the top level foo/bar,
    // this should refer to subtwo's `foo`
    // @has issue_55364/subtwo/fn.bar.html
    // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
    /// See [foo]
    pub fn bar() {}
}

// These are the function referred to by the module above with outer docs

/// See [bar]
pub fn foo() {}
/// See [foo]
pub fn bar() {}

// This module refers to the outer foo/bar by means of `super::`

// @has issue_55364/subthree/index.html
// This module should also refer to the top level foo/bar
// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
pub mod subthree {
    //! See either [foo][super::foo] or [bar][super::bar]
}

// Next we go *deeper* - In order to ensure it's not just "this or parent"
// we test `crate::` and a `super::super::...` chain
// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
pub mod subfour {
    pub mod subfive {
        pub mod subsix {
            pub mod subseven {
                pub mod subeight {
                    /// See [other foo][crate::subone::foo]
                    pub fn foo() {}
                    /// See [other bar][super::super::super::super::super::subtwo::bar]
                    pub fn bar() {}
                }
            }
        }
    }
}
<|endoftext|>