<commit_before>use crate::io::util::lines::{lines, Lines};
use crate::io::util::read_line::{read_line, ReadLine};
use crate::io::util::read_until::{read_until, ReadUntil};
use crate::io::util::split::{split, Split};
use crate::io::AsyncBufRead;

cfg_io_util! {
    /// An extension trait which adds utility methods to `AsyncBufRead` types.
    pub trait AsyncBufReadExt: AsyncBufRead {
        /// Creates a future which will read all the bytes associated with this I/O
        /// object into `buf` until the delimiter `byte` or EOF is reached.
        /// This method is the async equivalent to [`BufRead::read_until`](std::io::BufRead::read_until).
        ///
        /// This function will read bytes from the underlying stream until the
        /// delimiter or EOF is found. Once found, all bytes up to, and including,
        /// the delimiter (if found) will be appended to `buf`.
        ///
        /// The returned future will resolve to the number of bytes read once the read
        /// operation is completed.
        ///
        /// In the case of an error the buffer and the object will be discarded, with
        /// the error yielded.
        fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntil<'a, Self>
        where
            Self: Unpin,
        {
            read_until(self, byte, buf)
        }

        /// Creates a future which will read all the bytes associated with this I/O
        /// object into `buf` until a newline (the 0xA byte) or EOF is reached,
        /// This method is the async equivalent to [`BufRead::read_line`](std::io::BufRead::read_line).
        ///
        /// This function will read bytes from the underlying stream until the
        /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
        /// up to, and including, the delimiter (if found) will be appended to
        /// `buf`.
        ///
        /// The returned future will resolve to the number of bytes read once the read
        /// operation is completed.
        ///
        /// In the case of an error the buffer and the object will be discarded, with
        /// the error yielded.
        ///
        /// # Errors
        ///
        /// This function has the same error semantics as [`read_until`] and will
        /// also return an error if the read bytes are not valid UTF-8. If an I/O
        /// error is encountered then `buf` may contain some bytes already read in
        /// the event that all data read so far was valid UTF-8.
        ///
        /// [`read_until`]: AsyncBufReadExt::read_until
        /// ------------
        /// Read all bytes until a newline (the 0xA byte) is reached, and append
        /// them to the provided buffer.
        ///
        /// This function will read bytes from the underlying stream until the
        /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
        /// up to, and including, the delimiter (if found) will be appended to
        /// `buf`.
        ///
        /// If successful, this function will return the total number of bytes read.
        ///
        /// If this function returns `Ok(0)`, the stream has reached EOF.
        ///
        /// # Errors
        ///
        /// This function has the same error semantics as [`read_until`] and will
        /// also return an error if the read bytes are not valid UTF-8. If an I/O
        /// error is encountered then `buf` may contain some bytes already read in
        /// the event that all data read so far was valid UTF-8.
        ///
        /// [`read_until`]: AsyncBufReadExt::read_until
        ///
        /// # Examples
        ///
        /// [`std::io::Cursor`][`Cursor`] is a type that implements
        /// `AsyncBufRead`. In this example, we use [`Cursor`] to read all the
        /// lines in a byte slice:
        ///
        /// [`Cursor`]: std::io::Cursor
        ///
        /// ```
        /// use tokio::io::AsyncBufReadExt;
        ///
        /// use std::io::Cursor;
        ///
        /// #[tokio::main]
        /// async fn main() {
        ///     let mut cursor = Cursor::new(b"foo\nbar");
        ///     let mut buf = String::new();
        ///
        ///     // cursor is at 'f'
        ///     let num_bytes = cursor.read_line(&mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 4);
        ///     assert_eq!(buf, "foo\n");
        ///     buf.clear();
        ///
        ///     // cursor is at 'b'
        ///     let num_bytes = cursor.read_line(&mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 3);
        ///     assert_eq!(buf, "bar");
        ///     buf.clear();
        ///
        ///     // cursor is at EOF
        ///     let num_bytes = cursor.read_line(&mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 0);
        ///     assert_eq!(buf, "");
        /// }
        /// ```
        fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self>
        where
            Self: Unpin,
        {
            read_line(self, buf)
        }

        /// Returns a stream of the contents of this reader split on the byte
        /// `byte`.
        ///
        /// This method is the asynchronous equivalent to
        /// [`BufRead::split`](std::io::BufRead::split).
        ///
        /// The stream returned from this function will yield instances of
        /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
        /// the delimiter byte at the end.
        ///
        /// [`io::Result`]: std::io::Result
        /// [`Vec<u8>`]: std::vec::Vec
        ///
        /// # Errors
        ///
        /// Each item of the stream has the same error semantics as
        /// [`AsyncBufReadExt::read_until`](AsyncBufReadExt::read_until).
        ///
        /// # Examples
        ///
        /// ```
        /// # use tokio::io::AsyncBufRead;
        /// use tokio::io::AsyncBufReadExt;
        ///
        /// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
        /// let mut segments = my_buf_read.split(b'f');
        ///
        /// while let Some(segment) = segments.next_segment().await? {
        ///     println!("length = {}", segment.len())
        /// }
        /// # Ok(())
        /// # }
        /// ```
        fn split(self, byte: u8) -> Split<Self>
        where
            Self: Sized + Unpin,
        {
            split(self, byte)
        }

        /// Returns a stream over the lines of this reader.
        /// This method is the async equivalent to [`BufRead::lines`](std::io::BufRead::lines).
        ///
        /// The stream returned from this function will yield instances of
        /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
        /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
        ///
        /// [`io::Result`]: std::io::Result
        /// [`String`]: String
        ///
        /// # Errors
        ///
        /// Each line of the stream has the same error semantics as [`AsyncBufReadExt::read_line`].
        ///
        /// [`AsyncBufReadExt::read_line`]: AsyncBufReadExt::read_line
        fn lines(self) -> Lines<Self>
        where
            Self: Sized,
        {
            lines(self)
        }
    }
}

impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}
<commit_msg>doc: improve AsyncBufReadExt API documentation (#1868)<commit_after>use crate::io::util::lines::{lines, Lines};
use crate::io::util::read_line::{read_line, ReadLine};
use crate::io::util::read_until::{read_until, ReadUntil};
use crate::io::util::split::{split, Split};
use crate::io::AsyncBufRead;

cfg_io_util! {
    /// An extension trait which adds utility methods to `AsyncBufRead` types.
    pub trait AsyncBufReadExt: AsyncBufRead {
        /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
        ///
        /// Equivalent to:
        ///
        /// ```ignore
        /// async fn read_until(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>;
        /// ```
        ///
        /// This function will read bytes from the underlying stream until the
        /// delimiter or EOF is found. Once found, all bytes up to, and including,
        /// the delimiter (if found) will be appended to `buf`.
        ///
        /// If successful, this function will return the total number of bytes read.
        ///
        /// # Errors
        ///
        /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
        /// will otherwise return any errors returned by [`fill_buf`].
        ///
        /// If an I/O error is encountered then all bytes read so far will be
        /// present in `buf` and its length will have been adjusted appropriately.
        ///
        /// [`fill_buf`]: AsyncBufRead::poll_fill_buf
        /// [`ErrorKind::Interrupted`]: std::io::ErrorKind::Interrupted
        ///
        /// # Examples
        ///
        /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
        /// this example, we use [`Cursor`] to read all the bytes in a byte slice
        /// in hyphen delimited segments:
        ///
        /// [`Cursor`]: std::io::Cursor
        ///
        /// ```
        /// use tokio::io::AsyncBufReadExt;
        ///
        /// use std::io::Cursor;
        ///
        /// #[tokio::main]
        /// async fn main() {
        ///     let mut cursor = Cursor::new(b"lorem-ipsum");
        ///     let mut buf = vec![];
        ///
        ///     // cursor is at 'l'
        ///     let num_bytes = cursor.read_until(b'-', &mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 6);
        ///     assert_eq!(buf, b"lorem-");
        ///     buf.clear();
        ///
        ///     // cursor is at 'i'
        ///     let num_bytes = cursor.read_until(b'-', &mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 5);
        ///     assert_eq!(buf, b"ipsum");
        ///     buf.clear();
        ///
        ///     // cursor is at EOF
        ///     let num_bytes = cursor.read_until(b'-', &mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///     assert_eq!(num_bytes, 0);
        ///     assert_eq!(buf, b"");
        /// }
        /// ```
        fn read_until<'a>(&'a mut self, byte: u8, buf: &'a mut Vec<u8>) -> ReadUntil<'a, Self>
        where
            Self: Unpin,
        {
            read_until(self, byte, buf)
        }

        /// Read all bytes until a newline (the 0xA byte) is reached, and append
        /// them to the provided buffer.
        ///
        /// Equivalent to:
        ///
        /// ```ignore
        /// async fn read_line(&mut self, buf: &mut String) -> io::Result<usize>;
        /// ```
        ///
        /// This function will read bytes from the underlying stream until the
        /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
        /// up to, and including, the delimiter (if found) will be appended to
        /// `buf`.
        ///
        /// If successful, this function will return the total number of bytes read.
        ///
        /// If this function returns `Ok(0)`, the stream has reached EOF.
        ///
        /// # Errors
        ///
        /// This function has the same error semantics as [`read_until`] and will
        /// also return an error if the read bytes are not valid UTF-8. If an I/O
        /// error is encountered then `buf` may contain some bytes already read in
        /// the event that all data read so far was valid UTF-8.
        ///
        /// [`read_until`]: AsyncBufReadExt::read_until
        ///
        /// # Examples
        ///
        /// [`std::io::Cursor`][`Cursor`] is a type that implements
        /// `AsyncBufRead`. In this example, we use [`Cursor`] to read all the
        /// lines in a byte slice:
        ///
        /// [`Cursor`]: std::io::Cursor
        ///
        /// ```
        /// use tokio::io::AsyncBufReadExt;
        ///
        /// use std::io::Cursor;
        ///
        /// #[tokio::main]
        /// async fn main() {
        ///     let mut cursor = Cursor::new(b"foo\nbar");
        ///     let mut buf = String::new();
        ///
        ///     // cursor is at 'f'
        ///     let num_bytes = cursor.read_line(&mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 4);
        ///     assert_eq!(buf, "foo\n");
        ///     buf.clear();
        ///
        ///     // cursor is at 'b'
        ///     let num_bytes = cursor.read_line(&mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 3);
        ///     assert_eq!(buf, "bar");
        ///     buf.clear();
        ///
        ///     // cursor is at EOF
        ///     let num_bytes = cursor.read_line(&mut buf)
        ///         .await
        ///         .expect("reading from cursor won't fail");
        ///
        ///     assert_eq!(num_bytes, 0);
        ///     assert_eq!(buf, "");
        /// }
        /// ```
        fn read_line<'a>(&'a mut self, buf: &'a mut String) -> ReadLine<'a, Self>
        where
            Self: Unpin,
        {
            read_line(self, buf)
        }

        /// Returns a stream of the contents of this reader split on the byte
        /// `byte`.
        ///
        /// This method is the asynchronous equivalent to
        /// [`BufRead::split`](std::io::BufRead::split).
        ///
        /// The stream returned from this function will yield instances of
        /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
        /// the delimiter byte at the end.
        ///
        /// [`io::Result`]: std::io::Result
        /// [`Vec<u8>`]: std::vec::Vec
        ///
        /// # Errors
        ///
        /// Each item of the stream has the same error semantics as
        /// [`AsyncBufReadExt::read_until`](AsyncBufReadExt::read_until).
        ///
        /// # Examples
        ///
        /// ```
        /// # use tokio::io::AsyncBufRead;
        /// use tokio::io::AsyncBufReadExt;
        ///
        /// # async fn dox(my_buf_read: impl AsyncBufRead + Unpin) -> std::io::Result<()> {
        /// let mut segments = my_buf_read.split(b'f');
        ///
        /// while let Some(segment) = segments.next_segment().await? {
        ///     println!("length = {}", segment.len())
        /// }
        /// # Ok(())
        /// # }
        /// ```
        fn split(self, byte: u8) -> Split<Self>
        where
            Self: Sized + Unpin,
        {
            split(self, byte)
        }

        /// Returns a stream over the lines of this reader.
        /// This method is the async equivalent to [`BufRead::lines`](std::io::BufRead::lines).
        ///
        /// The stream returned from this function will yield instances of
        /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
        /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
        ///
        /// [`io::Result`]: std::io::Result
        /// [`String`]: String
        ///
        /// # Errors
        ///
        /// Each line of the stream has the same error semantics as [`AsyncBufReadExt::read_line`].
        ///
        /// # Examples
        ///
        /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
        /// this example, we use [`Cursor`] to iterate over all the lines in a byte
        /// slice.
        ///
        /// [`Cursor`]: std::io::Cursor
        ///
        /// ```
        /// use tokio::io::AsyncBufReadExt;
        ///
        /// use futures::{StreamExt};
        /// use std::io::Cursor;
        ///
        /// #[tokio::main]
        /// async fn main() {
        ///     let cursor = Cursor::new(b"lorem\nipsum\r\ndolor");
        ///
        ///     let mut lines = cursor.lines().map(|res| res.unwrap());
        ///
        ///     assert_eq!(lines.next().await, Some(String::from("lorem")));
        ///     assert_eq!(lines.next().await, Some(String::from("ipsum")));
        ///     assert_eq!(lines.next().await, Some(String::from("dolor")));
        ///     assert_eq!(lines.next().await, None);
        /// }
        /// ```
        ///
        /// [`AsyncBufReadExt::read_line`]: AsyncBufReadExt::read_line
        fn lines(self) -> Lines<Self>
        where
            Self: Sized,
        {
            lines(self)
        }
    }
}

impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}
<|endoftext|>


<commit_before>//! This module contains the transfer protocol handlers.
//!
//! The general architecture is as follows:
//!
//! ```plain
//! +--------+   new index   +------+
//! |        | +-----------> |      |
//! | Source |               | Sink |
//! |        | request block |      |
//! |        | <-----------+ |      |
//! |        |               |      |
//! |        |  send block   |      |
//! |        | +-----------> |      |
//! +--------+               +------+
//! ```
//!
//! First the old index is computed and loaded in full.
//!
//! Then, the new index is fed in either all at once or in a streaming fashion.
//!
//! The sink will request blocks that are missing from the destination,
//! which are fed in as they are received.

pub mod fs;

use std::path::{Path, PathBuf};

use crate::{Error, HashDigest};
use crate::index::Index;

/// The sink, representing where the files are being sent.
///
/// This is relative to a single process, e.g. the sending side has a sink
/// encapsulating some network protocol, and the receiving side has a sink that
/// actually updates files.
pub trait Sink {
    /// Start on a new file
    fn new_file(&mut self, path: &Path, modified: chrono::DateTime<chrono::Utc>) -> Result<(), Error>;

    /// Feed entry from the new index
    fn new_block(&mut self, hash: &HashDigest, size: usize) -> Result<(), Error>;

    /// End of files
    fn end_files(&mut self) -> Result<(), Error>;

    /// Feed a block that was requested
    fn feed_block(&mut self, hash: &HashDigest, block: &[u8]) -> Result<(), Error>;

    /// Ask which blocks to get next
    fn next_requested_block(&mut self) -> Result<Option<HashDigest>, Error>;

    /// Are we waiting on blocks?
    fn is_missing_blocks(&self) -> Result<bool, Error>;
}

/// Events that are received from the index data.
#[derive(Debug)]
pub enum IndexEvent {
    /// Start a new file (e.g. next `NewBlock` are blocks of that file)
    NewFile(PathBuf, chrono::DateTime<chrono::Utc>),

    /// Add a new block to the current file
    NewBlock(HashDigest, usize),

    /// End of the whole transfer
    End,
}

/// The source, representing where the files are coming from.
///
/// This is relative to a single process, e.g. the sending side has a source
/// that reads from files, and the receiving side has a source that reads from
/// the network.
pub trait Source {
    /// Get the next event from the index data
    fn next_from_index(&mut self) -> Result<Option<IndexEvent>, Error>;

    /// Asynchronously request a block from this source
    fn request_block(&mut self, hash: &HashDigest) -> Result<(), Error>;

    /// Get a block that was previously requested
    fn get_next_block(&mut self) -> Result<Option<(HashDigest, Vec<u8>)>, Error>;
}

pub trait SinkExt {
    /// Feed a whole new index
    fn new_index(&mut self, new_index: &Index) -> Result<(), Error>;
}

impl<R: Sink> SinkExt for R {
    /// Feed a whole new index
    fn new_index(&mut self, new_index: &Index) -> Result<(), Error> {
        // TODO: Go over index and feed it to new_file()/new_block()
        // Maybe can be more efficient? Don't know
        unimplemented!()
    }
}

impl<R: Sink + ?Sized> Sink for Box<R> {
    fn new_file(&mut self, path: &Path, modified: chrono::DateTime<chrono::Utc>) -> Result<(), Error> {
        (**self).new_file(path, modified)
    }

    fn new_block(&mut self, hash: &HashDigest, size: usize) -> Result<(), Error> {
        (**self).new_block(hash, size)
    }

    fn end_files(&mut self) -> Result<(), Error> {
        (**self).end_files()
    }

    fn feed_block(&mut self, hash: &HashDigest, block: &[u8]) -> Result<(), Error> {
        (**self).feed_block(hash, block)
    }

    fn next_requested_block(&mut self) -> Result<Option<HashDigest>, Error> {
        (**self).next_requested_block()
    }

    fn is_missing_blocks(&self) -> Result<bool, Error> {
        (**self).is_missing_blocks()
    }
}

impl<S: Source + ?Sized> Source for Box<S> {
    fn next_from_index(&mut self) -> Result<Option<IndexEvent>, Error> {
        (**self).next_from_index()
    }

    fn request_block(&mut self, hash: &HashDigest) -> Result<(), Error> {
        (**self).request_block(hash)
    }

    fn get_next_block(&mut self) -> Result<Option<(HashDigest, Vec<u8>)>, Error> {
        (**self).get_next_block()
    }
}

/// Wrapper for ownership reasons
///
/// This only exists to hold the rusqlite `Connection`, which has to outlive
/// the transaction used by the `Sink`.
pub trait SinkWrapper {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Sink + 'a>, Error>;
}

impl<RW: SinkWrapper + ?Sized> SinkWrapper for Box<RW> {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Sink + 'a>, Error> {
        (**self).open()
    }
}

/// Wrapper for ownership reasons
///
/// This only exists to hold the rusqlite `Connection`, which has to outlive
/// the transaction used by the `Source`.
pub trait SourceWrapper {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Source + 'a>, Error>;
}

impl<SW: SourceWrapper + ?Sized> SourceWrapper for Box<SW> {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Source + 'a>, Error> {
        (**self).open()
    }
}

pub fn do_sync<S: Source, R: Sink>(mut source: S, mut sink: R) -> Result<(), Error> {
    let mut instructions = true;
    while instructions || sink.is_missing_blocks()? {
        // Things are done in order so that bandwidth is used in a smart way
        // For example, if you block on sending block data, you will have
        // received more block requests in the next loop, and you'll only
        // transmit (sender side) or process (receiver side) index instructions
        // when there's nothing better to do
        if let Some(hash) = sink.next_requested_block()? {
            // Block requests
            source.request_block(&hash)?; // can block on HTTP receiver side
        } else if let Some((hash, block)) =
            source.get_next_block()? // blocks on receiver side
        {
            // Block data
            sink.feed_block(&hash, &block)?; // blocks on sender side
        } else if let Some(event) = source.next_from_index()? {
            // Index instructions
            match event {
                IndexEvent::NewFile(path, modified) => {
                    sink.new_file(&path, modified)?
                }
                IndexEvent::NewBlock(hash, size) => {
                    sink.new_block(&hash, size)?
                }
                IndexEvent::End => {
                    sink.end_files()?;
                    instructions = false;
                }
            }
        }
    }
    Ok(())
}
<commit_msg>Implement Sink::new_index() to feed whole index<commit_after>//! This module contains the transfer protocol handlers.
//!
//! The general architecture is as follows:
//!
//! ```plain
//! +--------+   new index   +------+
//! |        | +-----------> |      |
//! | Source |               | Sink |
//! |        | request block |      |
//! |        | <-----------+ |      |
//! |        |               |      |
//! |        |  send block   |      |
//! |        | +-----------> |      |
//! +--------+               +------+
//! ```
//!
//! First the old index is computed and loaded in full.
//!
//! Then, the new index is fed in either all at once or in a streaming fashion.
//!
//! The sink will request blocks that are missing from the destination,
//! which are fed in as they are received.

pub mod fs;

use std::path::{Path, PathBuf};

use crate::{Error, HashDigest};
use crate::index::IndexTransaction;

/// The sink, representing where the files are being sent.
///
/// This is relative to a single process, e.g. the sending side has a sink
/// encapsulating some network protocol, and the receiving side has a sink that
/// actually updates files.
pub trait Sink {
    /// Start on a new file
    fn new_file(&mut self, path: &Path, modified: chrono::DateTime<chrono::Utc>) -> Result<(), Error>;

    /// Feed entry from the new index
    fn new_block(&mut self, hash: &HashDigest, size: usize) -> Result<(), Error>;

    /// End of files
    fn end_files(&mut self) -> Result<(), Error>;

    /// Feed a block that was requested
    fn feed_block(&mut self, hash: &HashDigest, block: &[u8]) -> Result<(), Error>;

    /// Ask which blocks to get next
    fn next_requested_block(&mut self) -> Result<Option<HashDigest>, Error>;

    /// Are we waiting on blocks?
    fn is_missing_blocks(&self) -> Result<bool, Error>;
}

/// Events that are received from the index data.
#[derive(Debug)]
pub enum IndexEvent {
    /// Start a new file (e.g. next `NewBlock` are blocks of that file)
    NewFile(PathBuf, chrono::DateTime<chrono::Utc>),

    /// Add a new block to the current file
    NewBlock(HashDigest, usize),

    /// End of the whole transfer
    End,
}

/// The source, representing where the files are coming from.
///
/// This is relative to a single process, e.g. the sending side has a source
/// that reads from files, and the receiving side has a source that reads from
/// the network.
pub trait Source {
    /// Get the next event from the index data
    fn next_from_index(&mut self) -> Result<Option<IndexEvent>, Error>;

    /// Asynchronously request a block from this source
    fn request_block(&mut self, hash: &HashDigest) -> Result<(), Error>;

    /// Get a block that was previously requested
    fn get_next_block(&mut self) -> Result<Option<(HashDigest, Vec<u8>)>, Error>;
}

pub trait SinkExt {
    /// Feed a whole new index
    fn new_index(&mut self, index: &IndexTransaction) -> Result<(), Error>;
}

impl<R: Sink> SinkExt for R {
    /// Feed a whole new index
    fn new_index(&mut self, index: &IndexTransaction) -> Result<(), Error> {
        for (file_id, path, modified) in index.list_files()? {
            self.new_file(&path, modified)?;
            for (hash, _offset, size) in index.list_file_blocks(file_id)? {
                self.new_block(&hash, size)?;
            }
        }
        self.end_files()?;
        Ok(())
    }
}

impl<R: Sink + ?Sized> Sink for Box<R> {
    fn new_file(&mut self, path: &Path, modified: chrono::DateTime<chrono::Utc>) -> Result<(), Error> {
        (**self).new_file(path, modified)
    }

    fn new_block(&mut self, hash: &HashDigest, size: usize) -> Result<(), Error> {
        (**self).new_block(hash, size)
    }

    fn end_files(&mut self) -> Result<(), Error> {
        (**self).end_files()
    }

    fn feed_block(&mut self, hash: &HashDigest, block: &[u8]) -> Result<(), Error> {
        (**self).feed_block(hash, block)
    }

    fn next_requested_block(&mut self) -> Result<Option<HashDigest>, Error> {
        (**self).next_requested_block()
    }

    fn is_missing_blocks(&self) -> Result<bool, Error> {
        (**self).is_missing_blocks()
    }
}

impl<S: Source + ?Sized> Source for Box<S> {
    fn next_from_index(&mut self) -> Result<Option<IndexEvent>, Error> {
        (**self).next_from_index()
    }

    fn request_block(&mut self, hash: &HashDigest) -> Result<(), Error> {
        (**self).request_block(hash)
    }

    fn get_next_block(&mut self) -> Result<Option<(HashDigest, Vec<u8>)>, Error> {
        (**self).get_next_block()
    }
}

/// Wrapper for ownership reasons
///
/// This only exists to hold the rusqlite `Connection`, which has to outlive
/// the transaction used by the `Sink`.
pub trait SinkWrapper {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Sink + 'a>, Error>;
}

impl<RW: SinkWrapper + ?Sized> SinkWrapper for Box<RW> {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Sink + 'a>, Error> {
        (**self).open()
    }
}

/// Wrapper for ownership reasons
///
/// This only exists to hold the rusqlite `Connection`, which has to outlive
/// the transaction used by the `Source`.
pub trait SourceWrapper {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Source + 'a>, Error>;
}

impl<SW: SourceWrapper + ?Sized> SourceWrapper for Box<SW> {
    fn open<'a>(&'a mut self) -> Result<Box<dyn Source + 'a>, Error> {
        (**self).open()
    }
}

pub fn do_sync<S: Source, R: Sink>(mut source: S, mut sink: R) -> Result<(), Error> {
    let mut instructions = true;
    while instructions || sink.is_missing_blocks()? {
        // Things are done in order so that bandwidth is used in a smart way
        // For example, if you block on sending block data, you will have
        // received more block requests in the next loop, and you'll only
        // transmit (sender side) or process (receiver side) index instructions
        // when there's nothing better to do
        if let Some(hash) = sink.next_requested_block()? {
            // Block requests
            source.request_block(&hash)?; // can block on HTTP receiver side
        } else if let Some((hash, block)) =
            source.get_next_block()? // blocks on receiver side
        {
            // Block data
            sink.feed_block(&hash, &block)?; // blocks on sender side
        } else if let Some(event) = source.next_from_index()? {
            // Index instructions
            match event {
                IndexEvent::NewFile(path, modified) => {
                    sink.new_file(&path, modified)?
                }
                IndexEvent::NewBlock(hash, size) => {
                    sink.new_block(&hash, size)?
                }
                IndexEvent::End => {
                    sink.end_files()?;
                    instructions = false;
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use super::*;

mod bad;
mod doubled_bytes;
mod ignore_garbage;
mod pairs;
mod single_bytes;
mod wrap;

#[cfg(feature = "nightly")]
mod bench;

#[test]
// this doesn't really fit anywhere else
fn correct_b2s_types() {
    #[cfg(feature = "fnv")]
    let _: &::fnv::FnvBuildHasher = BLOCK_START_TO_INDEX.hasher();
    #[cfg(not(feature = "fnv"))]
    let _: &::std::collections::hash_map::RandomState = BLOCK_START_TO_INDEX.hasher();
}
<commit_msg>Add Send + Sync tests for Error and WrapOptions<commit_after>use super::*;

mod bad;
mod doubled_bytes;
mod ignore_garbage;
mod pairs;
mod single_bytes;
mod wrap;

#[cfg(feature = "nightly")]
mod bench;

#[test]
fn correct_b2s_types() {
    #[cfg(feature = "fnv")]
    let _: &::fnv::FnvBuildHasher = BLOCK_START_TO_INDEX.hasher();
    #[cfg(not(feature = "fnv"))]
    let _: &::std::collections::hash_map::RandomState = BLOCK_START_TO_INDEX.hasher();
}

#[test]
fn error_send() {
    fn assert_send<T: Send>() {}
    assert_send::<Error>();
}

#[test]
fn error_sync() {
    fn assert_sync<T: Sync>() {}
    assert_sync::<Error>();
}

#[test]
fn wrapoptions_send() {
    fn assert_send<T: Send>() {}
    assert_send::<WrapOptions>();
}

#[test]
fn wrapoptions_sync() {
    fn assert_sync<T: Sync>() {}
    assert_sync::<WrapOptions>();
}
<|endoftext|>


<commit_before>#![allow(
    clippy::cast_sign_loss,
    clippy::default_trait_access,
    clippy::doc_markdown,
    clippy::enum_glob_use,
    clippy::filter_map,
    clippy::inherent_to_string,
    clippy::items_after_statements,
    clippy::large_enum_variant,
    clippy::match_bool,
    clippy::match_same_arms,
    clippy::module_name_repetitions,
    clippy::needless_pass_by_value,
    clippy::new_without_default,
    clippy::nonminimal_bool,
    clippy::option_if_let_else,
    clippy::or_fun_call,
    clippy::redundant_else,
    clippy::shadow_unrelated,
    clippy::similar_names,
    clippy::single_match,
    clippy::single_match_else,
    clippy::too_many_arguments,
    clippy::too_many_lines,
    clippy::toplevel_ref_arg,
    clippy::useless_let_if_seq
)]

extern crate proc_macro;

mod derive;
mod expand;
mod syntax;
mod type_id;

use crate::syntax::file::Module;
use crate::syntax::namespace::Namespace;
use crate::syntax::qualified::QualifiedName;
use crate::type_id::Crate;
use proc_macro::TokenStream;
use syn::parse::{Parse, ParseStream, Parser, Result};
use syn::parse_macro_input;

/// `#[cxx::bridge] mod ffi { ... }`
///
/// Refer to the crate-level documentation for the explanation of how this macro
/// is intended to be used.
///
/// The only additional thing to note here is namespace support — if the
/// types and functions on the `extern "C++"` side of our bridge are in a
/// namespace, specify that namespace as an argument of the cxx::bridge
/// attribute macro.
///
/// ```
/// #[cxx::bridge(namespace = "mycompany::rust")]
/// # mod ffi {}
/// ```
///
/// The types and functions from the `extern "Rust"` side of the bridge will be
/// placed into that same namespace in the generated C++ code.
#[proc_macro_attribute]
pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
    let _ = syntax::error::ERRORS;

    let namespace = match Namespace::parse_bridge_attr_namespace.parse(args) {
        Ok(namespace) => namespace,
        Err(err) => return err.to_compile_error().into(),
    };
    let mut ffi = parse_macro_input!(input as Module);
    ffi.namespace = namespace;

    expand::bridge(ffi)
        .unwrap_or_else(|err| err.to_compile_error())
        .into()
}

#[proc_macro]
pub fn type_id(input: TokenStream) -> TokenStream {
    struct TypeId {
        krate: Crate,
        path: QualifiedName,
    }

    impl Parse for TypeId {
        fn parse(input: ParseStream) -> Result<Self> {
            let krate = input.parse().map(Crate::DollarCrate)?;
            let path = QualifiedName::parse_quoted_or_unquoted(input)?;
            Ok(TypeId { krate, path })
        }
    }

    let arg = parse_macro_input!(input as TypeId);
    type_id::expand(arg.krate, arg.path).into()
}
<commit_msg>Hide underlying type_id proc macro from rustdoc<commit_after>#![allow(
    clippy::cast_sign_loss,
    clippy::default_trait_access,
    clippy::doc_markdown,
    clippy::enum_glob_use,
    clippy::filter_map,
    clippy::inherent_to_string,
    clippy::items_after_statements,
    clippy::large_enum_variant,
    clippy::match_bool,
    clippy::match_same_arms,
    clippy::module_name_repetitions,
    clippy::needless_pass_by_value,
    clippy::new_without_default,
    clippy::nonminimal_bool,
    clippy::option_if_let_else,
    clippy::or_fun_call,
    clippy::redundant_else,
    clippy::shadow_unrelated,
    clippy::similar_names,
    clippy::single_match,
    clippy::single_match_else,
    clippy::too_many_arguments,
    clippy::too_many_lines,
    clippy::toplevel_ref_arg,
    clippy::useless_let_if_seq
)]

extern crate proc_macro;

mod derive;
mod expand;
mod syntax;
mod type_id;

use crate::syntax::file::Module;
use crate::syntax::namespace::Namespace;
use crate::syntax::qualified::QualifiedName;
use crate::type_id::Crate;
use proc_macro::TokenStream;
use syn::parse::{Parse, ParseStream, Parser, Result};
use syn::parse_macro_input;

/// `#[cxx::bridge] mod ffi { ... }`
///
/// Refer to the crate-level documentation for the explanation of how this macro
/// is intended to be used.
///
/// The only additional thing to note here is namespace support — if the
/// types and functions on the `extern "C++"` side of our bridge are in a
/// namespace, specify that namespace as an argument of the cxx::bridge
/// attribute macro.
///
/// ```
/// #[cxx::bridge(namespace = "mycompany::rust")]
/// # mod ffi {}
/// ```
///
/// The types and functions from the `extern "Rust"` side of the bridge will be
/// placed into that same namespace in the generated C++ code.
#[proc_macro_attribute]
pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
    let _ = syntax::error::ERRORS;

    let namespace = match Namespace::parse_bridge_attr_namespace.parse(args) {
        Ok(namespace) => namespace,
        Err(err) => return err.to_compile_error().into(),
    };
    let mut ffi = parse_macro_input!(input as Module);
    ffi.namespace = namespace;

    expand::bridge(ffi)
        .unwrap_or_else(|err| err.to_compile_error())
        .into()
}

#[doc(hidden)]
#[proc_macro]
pub fn type_id(input: TokenStream) -> TokenStream {
    struct TypeId {
        krate: Crate,
        path: QualifiedName,
    }

    impl Parse for TypeId {
        fn parse(input: ParseStream) -> Result<Self> {
            let krate = input.parse().map(Crate::DollarCrate)?;
            let path = QualifiedName::parse_quoted_or_unquoted(input)?;
            Ok(TypeId { krate, path })
        }
    }

    let arg = parse_macro_input!(input as TypeId);
    type_id::expand(arg.krate, arg.path).into()
}
<|endoftext|>


<commit_before>#![crate_type="dylib"]
#![feature(unique, shared)]

mod classfactory; pub use classfactory::*;
mod combox; pub use combox::*;
mod comrc; pub use comrc::*;
mod comitf; pub use comitf::*;
mod bstr; pub use bstr::*;
mod guid; pub use guid::GUID;
mod error; pub use error::{return_hresult, get_last_error, ComError};

// The crate doesn't really need the macros. However Rust will complain that
// the import does nothing if we don't define #[macro_use]. Once we define
// #[macro_use] to get rid of that warning, Rust will complain that the
// #[macro_use] does nothing. Fortunately THAT warning comes with a named
// warning option so we can allow that explicitly.
//
// Unfortunately clippy disagrees on the macro_use being unused and claims that
// the unused_imports attribute is useless. So now we also need to tell clippy
// to ignore useless attributes in this scenario! \:D/
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
#[allow(unused_imports)]
#[macro_use]
extern crate intercom_attributes;
pub use intercom_attributes::*;

/// Raw COM pointer type.
pub type RawComPtr = *mut std::os::raw::c_void;

/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

/// COM error result value.
pub type HRESULT = i32;

/// `HRESULT` indicating the operation completed successfully.
pub const S_OK : HRESULT = 0;

/// `HRESULT` indicating the operation completed successfully and returned FALSE.
pub const S_FALSE : HRESULT = 1;

/// `HRESULT` for unimplemented functionality.
#[allow(overflowing_literals)]
pub const E_NOTIMPL : HRESULT = 0x8000_4001 as HRESULT;

/// `HRESULT` indicating the type does not support the requested interface.
#[allow(overflowing_literals)]
pub const E_NOINTERFACE : HRESULT = 0x8000_4002 as HRESULT;

/// `HRESULT` indicating a pointer parameter was invalid.
#[allow(overflowing_literals)]
pub const E_POINTER : HRESULT = 0x8000_4003 as HRESULT;

/// `HRESULT` for aborted operation.
#[allow(overflowing_literals)]
pub const E_ABORT : HRESULT = 0x8000_4004 as HRESULT;

/// `HRESULT` for unspecified failure.
#[allow(overflowing_literals)]
pub const E_FAIL : HRESULT = 0x8000_4005 as HRESULT;

/// `HRESULT` for invalid argument.
#[allow(overflowing_literals)]
pub const E_INVALIDARG : HRESULT = 0x8007_0057 as HRESULT;

/// `IUnknown` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IUnknown : GUID = GUID {
    data1: 0x0000_0000, data2: 0x0000, data3: 0x0000,
    data4: [ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 ]
};

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory : GUID = GUID {
    data1: 0x0000_0001, data2: 0x0000, data3: 0x0000,
    data4: [ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 ]
};

/// `ISupportErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_ISupportErrorInfo : GUID = GUID {
    data1: 0xDF0B_3D60, data2: 0x548F, data3: 0x101B,
    data4: [ 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19 ]
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo : GUID = GUID {
    data1: 0x1CF2_B120, data2: 0x547D, data3: 0x101B,
    data4: [ 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19 ]
};

/// `IUnknown` virtual table layout.
#[repr(C)]
pub struct IUnknownVtbl
{
    /// `QueryInterface` method pointer.
    pub query_interface : unsafe extern "stdcall" fn(
        s : RawComPtr,
        _riid : REFIID,
        out : *mut RawComPtr
    ) -> HRESULT,

    /// `AddRef` method pointer.
    pub add_ref: unsafe extern "stdcall" fn( s : RawComPtr ) -> u32,

    /// `Release` method pointer.
    pub release: unsafe extern "stdcall" fn( s : RawComPtr ) -> u32,
}

/// `ISupportErrorInfo` virtual table layout.
#[repr(C)]
pub struct ISupportErrorInfoVtbl
{
    /// `ISupportErrorInfo` inherits `IUnknown`.
    pub __base : IUnknownVtbl,

    /// `InterfaceSupportsErrorInfo` method pointer.
    pub interface_supports_error_info : unsafe extern "stdcall" fn(
        s : RawComPtr,
        riid : REFIID,
    ) -> HRESULT,
}

// Do we need this? Would rather not export this through an extern crate
// for another dll.
//
// com_library should have dllmain!() macro or similar that implements this
// together with the COM registration.
#[no_mangle]
#[allow(non_camel_case_types)]
pub extern "stdcall" fn DllMain(
    _dll_instance : *mut std::os::raw::c_void,
    _reason : u32,
    _reserved : *mut std::os::raw::c_void ) -> bool
{
    true
}

pub type ComResult<A> = Result<A, HRESULT>;

<commit_msg>Use #[com_attributes] to define built-in interfaces<commit_after>#![crate_type="dylib"]
#![feature(unique, shared)]

mod classfactory; pub use classfactory::*;
mod combox; pub use combox::*;
mod comrc; pub use comrc::*;
mod comitf; pub use comitf::*;
mod bstr; pub use bstr::*;
mod guid; pub use guid::GUID;
mod error; pub use error::{return_hresult, get_last_error, ComError};

// The crate doesn't really need the macros. However Rust will complain that
// the import does nothing if we don't define #[macro_use]. Once we define
// #[macro_use] to get rid of that warning, Rust will complain that the
// #[macro_use] does nothing. Fortunately THAT warning comes with a named
// warning option so we can allow that explicitly.
//
// Unfortunately clippy disagrees on the macro_use being unused and claims that
// the unused_imports attribute is useless. So now we also need to tell clippy
// to ignore useless attributes in this scenario! \:D/
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
#[allow(unused_imports)]
extern crate intercom_attributes;
pub use intercom_attributes::*;

// intercom_attributes use "intercom::" to qualify things in this crate.
// Declare such module here and import everything we have in it to make those
// references valid.
mod intercom {
    pub use ::*;
}

/// Raw COM pointer type.
pub type RawComPtr = *mut std::os::raw::c_void;

/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

/// COM error result value.
pub type HRESULT = i32;

/// `HRESULT` indicating the operation completed successfully.
pub const S_OK : HRESULT = 0;

/// `HRESULT` indicating the operation completed successfully and returned FALSE.
pub const S_FALSE : HRESULT = 1;

/// `HRESULT` for unimplemented functionality.
#[allow(overflowing_literals)]
pub const E_NOTIMPL : HRESULT = 0x8000_4001 as HRESULT;

/// `HRESULT` indicating the type does not support the requested interface.
#[allow(overflowing_literals)]
pub const E_NOINTERFACE : HRESULT = 0x8000_4002 as HRESULT;

/// `HRESULT` indicating a pointer parameter was invalid.
#[allow(overflowing_literals)]
pub const E_POINTER : HRESULT = 0x8000_4003 as HRESULT;

/// `HRESULT` for aborted operation.
#[allow(overflowing_literals)]
pub const E_ABORT : HRESULT = 0x8000_4004 as HRESULT;

/// `HRESULT` for unspecified failure.
#[allow(overflowing_literals)]
pub const E_FAIL : HRESULT = 0x8000_4005 as HRESULT;

/// `HRESULT` for invalid argument.
#[allow(overflowing_literals)]
pub const E_INVALIDARG : HRESULT = 0x8007_0057 as HRESULT;

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory : GUID = GUID {
    data1: 0x0000_0001, data2: 0x0000, data3: 0x0000,
    data4: [ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 ]
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo : GUID = GUID {
    data1: 0x1CF2_B120, data2: 0x547D, data3: 0x101B,
    data4: [ 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19 ]
};

mod interfaces {

    #[::com_interface( "00000000-0000-0000-C000-000000000046", NO_BASE )]
    pub trait IUnknown {
        fn query_interface( &self, riid : ::REFIID ) -> ::ComResult< ::RawComPtr >;
        fn add_ref( &self ) -> u32;
        fn release( &self ) -> u32;
    }

    #[::com_interface( "DF0B3D60-548F-101B-8E65-08002B2BD119" )]
    pub trait ISupportErrorInfo {
        fn interface_supports_error_info( &self, riid : ::REFIID ) -> ::HRESULT;
    }
}

pub use interfaces::__IUnknownVtbl as IUnknownVtbl;
pub use interfaces::IID_IUnknown;
pub use interfaces::IUnknown;

pub use interfaces::__ISupportErrorInfoVtbl as ISupportErrorInfoVtbl;
pub use interfaces::IID_ISupportErrorInfo;
pub use interfaces::ISupportErrorInfo;

// Do we need this? Would rather not export this through an extern crate
// for another dll.
//
// com_library should have dllmain!() macro or similar that implements this
// together with the COM registration.
#[no_mangle]
#[allow(non_camel_case_types)]
pub extern "stdcall" fn DllMain(
    _dll_instance : *mut std::os::raw::c_void,
    _reason : u32,
    _reserved : *mut std::os::raw::c_void ) -> bool
{
    true
}

pub type ComResult<A> = Result<A, HRESULT>;

<|endoftext|>


<commit_before>#![allow(
    dead_code,
    missing_copy_implementations,
    non_camel_case_types,
    non_snake_case,
    raw_pointer_derive,
   )]

#![feature(libc, plugin)]

extern crate libc;

pub use constants::*;
pub use ffi::*;

mod ffi;
mod constants;
<commit_msg>reenable lints<commit_after>#![allow(non_camel_case_types)]
#![feature(libc, plugin)]

extern crate libc;

pub use constants::*;
pub use ffi::*;

mod ffi;
mod constants;
<|endoftext|>


<commit_before>use crate::errors::*;
use std::convert::Into;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Component, Path, PathBuf};

/// Naively replaces any path seperator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String {
    use std::path::is_separator;
    path.chars()
        .map(|ch| if is_separator(ch) { '/' } else { ch })
        .collect::<String>()
}

/// Write the given data to a file, creating it first if necessary
pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> {
    let path = build_dir.join(filename);

    create_file(&path)?.write_all(content).map_err(Into::into)
}

/// Takes a path and returns a path containing just enough `../` to point to
/// the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the
/// directory from where the path starts.
///
/// ```rust
/// # use std::path::Path;
/// # use mdbook::utils::fs::path_to_root;
/// #
/// # fn main() {
/// let path = Path::new("some/relative/path");
/// assert_eq!(path_to_root(path), "../../");
/// # }
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where
/// it doesn't return the correct path.
/// Consider [submitting a new issue](https://github.com/rust-lang/mdBook/issues)
/// or a [pull-request](https://github.com/rust-lang/mdBook/pulls) to improve it.
pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
    debug!("path_to_root");
    // Remove filename and add "../" for every directory

    path.into()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file
/// it checks every directory in the path to see if it exists,
/// and if it does not it will be created.
pub fn create_file(path: &Path) -> Result<File> {
    debug!("Creating {}", path.display());

    // Construct path
    if let Some(p) = path.parent() {
        trace!("Parent directory is: {:?}", p);

        fs::create_dir_all(p)?;
    }

    File::create(path).map_err(Into::into)
}

/// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<()> {
    for item in fs::read_dir(dir)? {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                fs::remove_dir_all(item)?;
            } else {
                fs::remove_file(item)?;
            }
        }
    }
    Ok(())
}

/// Copies all files of a directory to another one except the files
/// with the extensions given in the `ext_blacklist` array
pub fn copy_files_except_ext(
    from: &Path,
    to: &Path,
    recursive: bool,
    ext_blacklist: &[&str],
) -> Result<()> {
    debug!(
        "Copying all files from {} to {} (blacklist: {:?})",
        from.display(),
        to.display(),
        ext_blacklist
    );

    // Check that from and to are different
    if from == to {
        return Ok(());
    }

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let metadata = entry.metadata()?;

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                fs::create_dir(&to.join(entry.file_name()))?;
            }

            copy_files_except_ext(
                &from.join(entry.file_name()),
                &to.join(entry.file_name()),
                true,
                ext_blacklist,
            )?;
        } else if metadata.is_file() {
            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!(
                "creating path for file: {:?}",
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );

            debug!(
                "Copying {:?} to {:?}",
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );
            fs::copy(
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name..."),
                ),
            )?;
        }
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn copy_files_except_ext_test() {
        let tmp = match tempfile::TempDir::new() {
            Ok(t) => t,
            Err(e) => panic!("Could not create a temp dir: {}", e),
        };

        // Create a couple of files
        if let Err(err) = fs::File::create(&tmp.path().join("file.txt")) {
            panic!("Could not create file.txt: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("file.md")) {
            panic!("Could not create file.md: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("file.png")) {
            panic!("Could not create file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("sub_dir")) {
            panic!("Could not create sub_dir: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists: {}", err);
        }
        if let Err(err) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt: {}", err);
        }

        // Create output dir
        if let Err(err) = fs::create_dir(&tmp.path().join("output")) {
            panic!("Could not create output: {}", err);
        }
        if let Err(err) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists: {}", err);
        }

        if let Err(e) =
            copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"])
        {
            panic!("Error while executing the function:\n{:?}", e);
        }

        // Check if the correct files where created
        if !(&tmp.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&tmp.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&tmp.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
    }
}
<commit_msg>Assure copy_files_except_ext(..) won't copy directories into itself (#1135)<commit_after>use crate::errors::*;
use std::convert::Into;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Component, Path, PathBuf};

/// Naively replaces any path seperator with a forward-slash '/'
pub fn normalize_path(path: &str) -> String {
    use std::path::is_separator;
    path.chars()
        .map(|ch| if is_separator(ch) { '/' } else { ch })
        .collect::<String>()
}

/// Write the given data to a file, creating it first if necessary
pub fn write_file<P: AsRef<Path>>(build_dir: &Path, filename: P, content: &[u8]) -> Result<()> {
    let path = build_dir.join(filename);

    create_file(&path)?.write_all(content).map_err(Into::into)
}

/// Takes a path and returns a path containing just enough `../` to point to
/// the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the
/// directory from where the path starts.
///
/// ```rust
/// # use std::path::Path;
/// # use mdbook::utils::fs::path_to_root;
/// #
/// # fn main() {
/// let path = Path::new("some/relative/path");
/// assert_eq!(path_to_root(path), "../../");
/// # }
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where
/// it doesn't return the correct path.
/// Consider [submitting a new issue](https://github.com/rust-lang/mdBook/issues)
/// or a [pull-request](https://github.com/rust-lang/mdBook/pulls) to improve it.
pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
    debug!("path_to_root");
    // Remove filename and add "../" for every directory

    path.into()
        .parent()
        .expect("")
        .components()
        .fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function creates a file and returns it. But before creating the file
/// it checks every directory in the path to see if it exists,
/// and if it does not it will be created.
pub fn create_file(path: &Path) -> Result<File> {
    debug!("Creating {}", path.display());

    // Construct path
    if let Some(p) = path.parent() {
        trace!("Parent directory is: {:?}", p);

        fs::create_dir_all(p)?;
    }

    File::create(path).map_err(Into::into)
}

/// Removes all the content of a directory but not the directory itself
pub fn remove_dir_content(dir: &Path) -> Result<()> {
    for item in fs::read_dir(dir)? {
        if let Ok(item) = item {
            let item = item.path();
            if item.is_dir() {
                fs::remove_dir_all(item)?;
            } else {
                fs::remove_file(item)?;
            }
        }
    }
    Ok(())
}

/// Copies all files of a directory to another one except the files
/// with the extensions given in the `ext_blacklist` array
pub fn copy_files_except_ext(
    from: &Path,
    to: &Path,
    recursive: bool,
    ext_blacklist: &[&str],
) -> Result<()> {
    debug!(
        "Copying all files from {} to {} (blacklist: {:?})",
        from.display(),
        to.display(),
        ext_blacklist
    );

    // Check that from and to are different
    if from == to {
        return Ok(());
    }

    // Is the destination inside of the source?
    if to.canonicalize()?.starts_with(from.canonicalize()?) {
        return Err(Error::from(format!(
            "Destination directory cannot be contained in source directory: '{}' is in '{}'",
            to.display(),
            from.display()
        )));
    }

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let metadata = entry.metadata()?;

        // If the entry is a dir and the recursive option is enabled, call itself
        if metadata.is_dir() && recursive {
            if entry.path() == to.to_path_buf() {
                continue;
            }

            // check if output dir already exists
            if !to.join(entry.file_name()).exists() {
                fs::create_dir(&to.join(entry.file_name()))?;
            }

            copy_files_except_ext(
                &from.join(entry.file_name()),
                &to.join(entry.file_name()),
                true,
                ext_blacklist,
            )?;
        } else if metadata.is_file() {
            // Check if it is in the blacklist
            if let Some(ext) = entry.path().extension() {
                if ext_blacklist.contains(&ext.to_str().unwrap()) {
                    continue;
                }
            }
            debug!(
                "creating path for file: {:?}",
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );

            debug!(
                "Copying {:?} to {:?}",
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name...")
                )
            );
            fs::copy(
                entry.path(),
                &to.join(
                    entry
                        .path()
                        .file_name()
                        .expect("a file should have a file name..."),
                ),
            )?;
        }
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::copy_files_except_ext;
    use std::fs;

    #[test]
    fn it_fails_when_destination_is_in_source() {
        let tmp = match tempfile::TempDir::new() {
            Ok(t) => t,
            Err(e) => panic!("Could not create a temp dir: {}", e),
        };
        let dst = tmp.path().join("destination");
        fs::create_dir(&dst).unwrap();
        assert!(
            format!("{:?}", copy_files_except_ext(tmp.path(), &dst, true, &[]))
                .contains("Destination directory cannot be contained in source directory: ")
        );
    }

    #[test]
    fn copy_files_except_ext_test() {
        let src = match tempfile::TempDir::new() {
            Ok(t) => t,
            Err(e) => panic!("Could not create a temp dir: {}", e),
        };

        // Create a couple of files
        if let Err(err) = fs::File::create(&src.path().join("file.txt")) {
            panic!("Could not create file.txt: {}", err);
        }
        if let Err(err) = fs::File::create(&src.path().join("file.md")) {
            panic!("Could not create file.md: {}", err);
        }
        if let Err(err) = fs::File::create(&src.path().join("file.png")) {
            panic!("Could not create file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&src.path().join("sub_dir")) {
            panic!("Could not create sub_dir: {}", err);
        }
        if let Err(err) = fs::File::create(&src.path().join("sub_dir/file.png")) {
            panic!("Could not create sub_dir/file.png: {}", err);
        }
        if let Err(err) = fs::create_dir(&src.path().join("sub_dir_exists")) {
            panic!("Could not create sub_dir_exists: {}", err);
        }
        if let Err(err) = fs::File::create(&src.path().join("sub_dir_exists/file.txt")) {
            panic!("Could not create sub_dir_exists/file.txt: {}", err);
        }

        // Create output dir
        let dst = match tempfile::TempDir::new() {
            Ok(t) => t,
            Err(e) => panic!("Could not create a temp dir: {}", e),
        };
        if let Err(err) = fs::create_dir(&dst.path().join("output")) {
            panic!("Could not create output: {}", err);
        }
        if let Err(err) = fs::create_dir(&dst.path().join("output/sub_dir_exists")) {
            panic!("Could not create output/sub_dir_exists: {}", err);
        }

        if let Err(e) =
            copy_files_except_ext(&src.path(), &dst.path().join("output"), true, &["md"])
        {
            panic!("Error while executing the function:\n{:?}", e);
        }

        // Check if the correct files where created
        if !(&dst.path().join("output/file.txt")).exists() {
            panic!("output/file.txt should exist")
        }
        if (&dst.path().join("output/file.md")).exists() {
            panic!("output/file.md should not exist")
        }
        if !(&dst.path().join("output/file.png")).exists() {
            panic!("output/file.png should exist")
        }
        if !(&dst.path().join("output/sub_dir/file.png")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
        if !(&dst.path().join("output/sub_dir_exists/file.txt")).exists() {
            panic!("output/sub_dir/file.png should exist")
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::definitions::InstallIfDifferent;
use serde::Deserialize;

#[derive(Deserialize, PartialEq, Debug)]
pub struct Imxkobs {
    pub filename: String,
    pub size: u64,
    pub sha256sum: String,

    pub install_if_different: Option<InstallIfDifferent>,
    #[serde(rename = "1k_padding")]
    #[serde(default)]
    pub padding_1k: bool,
    #[serde(default)]
    pub search_exponent: usize,
    #[serde(default)]
    pub chip_0_device_path: String,
    #[serde(default)]
    pub chip_1_device_path: String,
}

#[test]
fn deserialize() {
    use pretty_assertions::assert_eq;
    use serde_json::json;

    assert_eq!(
        Imxkobs {
            filename: "imxkobs-filename".to_string(),
            size: 1024,
            sha256sum: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
                .to_string(),

            install_if_different: None,
            padding_1k: true,
            search_exponent: 2,
            chip_0_device_path: "/dev/sda1".to_string(),
            chip_1_device_path: "/dev/sda2".to_string(),
        },
        serde_json::from_value::<Imxkobs>(json!({
            "filename": "imxkobs-filename",
            "sha256sum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            "size": 1024,
            "1k_padding": true,
            "search_exponent": 2,
            "chip_0_device_path": "/dev/sda1",
            "chip_1_device_path": "/dev/sda2",
        }))
        .unwrap()
    );
}
<commit_msg>updatehub-package-schema: Imxkobs chips path as Option<PathBuf><commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::definitions::InstallIfDifferent;
use serde::Deserialize;
use std::path::PathBuf;

#[derive(Deserialize, PartialEq, Debug)]
pub struct Imxkobs {
    pub filename: String,
    pub size: u64,
    pub sha256sum: String,

    pub install_if_different: Option<InstallIfDifferent>,
    #[serde(rename = "1k_padding")]
    #[serde(default)]
    pub padding_1k: bool,
    #[serde(default)]
    pub search_exponent: usize,
    #[serde(default)]
    pub chip_0_device_path: Option<PathBuf>,
    #[serde(default)]
    pub chip_1_device_path: Option<PathBuf>,
}

#[test]
fn deserialize() {
    use pretty_assertions::assert_eq;
    use serde_json::json;

    assert_eq!(
        Imxkobs {
            filename: "imxkobs-filename".to_string(),
            size: 1024,
            sha256sum: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
                .to_string(),

            install_if_different: None,
            padding_1k: true,
            search_exponent: 2,
            chip_0_device_path: Some(PathBuf::from("/dev/sda1")),
            chip_1_device_path: Some(PathBuf::from("/dev/sda2")),
        },
        serde_json::from_value::<Imxkobs>(json!({
            "filename": "imxkobs-filename",
            "sha256sum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            "size": 1024,
            "1k_padding": true,
            "search_exponent": 2,
            "chip_0_device_path": "/dev/sda1",
            "chip_1_device_path": "/dev/sda2",
        }))
        .unwrap()
    );
}
<|endoftext|>


<commit_before>#![feature(test)]

use sysinfo::get_current_pid;
use sysinfo::{DiskExt, SystemExt};

#[bench]
fn bench_new(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new();
    });
}

#[bench]
fn bench_new_all(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new_all();
    });
}

#[bench]
fn bench_refresh_all(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_all();
    });
}

#[bench]
fn bench_refresh_system(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    s.refresh_system();
    b.iter(move || {
        s.refresh_system();
    });
}

#[bench]
fn bench_refresh_processes(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_processes(); // to load the whole processes list a first time.
    b.iter(move || {
        s.refresh_processes();
    });
}

#[bench]
fn bench_refresh_process(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_all();
    // to be sure it'll exist for at least as long as we run
    let pid = get_current_pid().expect("failed to get current pid");
    b.iter(move || {
        s.refresh_process(pid);
    });
}

#[bench]
fn bench_refresh_disk(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    let disks = s.disks_mut();
    let disk = &mut disks[0];
    b.iter(move || {
        disk.refresh();
    });
}

#[bench]
fn bench_refresh_disks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_disks();
    });
}

#[bench]
fn bench_refresh_disks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_disks_list();
    });
}

#[bench]
fn bench_refresh_networks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_networks();
    });
}

#[bench]
fn bench_refresh_networks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_networks_list();
    });
}

#[bench]
fn bench_refresh_memory(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_memory();
    });
}

#[bench]
fn bench_refresh_cpu(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_cpu();
    });
}

#[bench]
fn bench_refresh_components(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components();
    });
}

#[bench]
fn bench_refresh_components_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components_list();
    });
}

#[bench]
fn bench_refresh_users_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_users_list();
    });
}
<commit_msg>Fix compile issue.<commit_after>#![feature(test)]

extern crate test;

use sysinfo::get_current_pid;
use sysinfo::{DiskExt, SystemExt};

#[bench]
fn bench_new(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new();
    });
}

#[bench]
fn bench_new_all(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new_all();
    });
}

#[bench]
fn bench_refresh_all(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_all();
    });
}

#[bench]
fn bench_refresh_system(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    s.refresh_system();
    b.iter(move || {
        s.refresh_system();
    });
}

#[bench]
fn bench_refresh_processes(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_processes(); // to load the whole processes list a first time.
    b.iter(move || {
        s.refresh_processes();
    });
}

#[bench]
fn bench_refresh_process(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_all();
    // to be sure it'll exist for at least as long as we run
    let pid = get_current_pid().expect("failed to get current pid");
    b.iter(move || {
        s.refresh_process(pid);
    });
}

#[bench]
fn bench_refresh_disk(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    let disks = s.disks_mut();
    let disk = &mut disks[0];
    b.iter(move || {
        disk.refresh();
    });
}

#[bench]
fn bench_refresh_disks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_disks();
    });
}

#[bench]
fn bench_refresh_disks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_disks_list();
    });
}

#[bench]
fn bench_refresh_networks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_networks();
    });
}

#[bench]
fn bench_refresh_networks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_networks_list();
    });
}

#[bench]
fn bench_refresh_memory(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_memory();
    });
}

#[bench]
fn bench_refresh_cpu(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_cpu();
    });
}

#[bench]
fn bench_refresh_components(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components();
    });
}

#[bench]
fn bench_refresh_components_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components_list();
    });
}

#[bench]
fn bench_refresh_users_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_users_list();
    });
}
<|endoftext|>


<commit_before>//! Layout handling

use rustwlc::handle::{WlcView, WlcOutput};
use std::rc::{Rc, Weak};

type Node = Box<Containable>;

#[derive(PartialEq, Clone, Copy)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Types of container
enum ContainerTypes {
    /// Root container, only one exists
    Root,
    /// WlcOutput/monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Layout mode for a container
enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Like i3, everything (workspaces, containers, views) are containable.
pub trait Containable {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Weak<Node>;

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Option<Vec<Weak<Node>>>;

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType;

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool;

    /// Removes this container and all of its children
    fn remove_container(&self) -> Result<(), &'static str>;

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool);

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64);

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64);

    /// Finds a parent container with the given type, if there is any
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<Rc<Node>> {
        let mut container = self.get_parent().upgrade();
        loop {
            if let Some(parent) = container {
                if parent.get_type() == type_ {
                    return Some(parent);
                }
                container = parent.get_parent().upgrade();
            } else {
                return None;
            }
        }
    }
}

/// View specific functions
pub trait Viewable {
    /// Determines if the view is full screen
    fn is_fullscreen(&self) -> bool;

    /// Figures out if the view is focused
    fn is_active(&self) -> bool;

    /// Returns true if this view is a parent is an ancestor of the child
    fn is_parent_of<T: Containable>(&self, child: T) -> bool;

    /// Returns true if this view is a child is an decedent of the parent
    fn is_child_of<T: Containable>(&self, parent: T) -> bool;

    /// Gets the active workspace of the view
    fn active_workspace<T: Containable>(&self) -> T;
}

struct Container {
    handle: Option<WlcOutput>,

    parent: Weak<Node>,
    children: Vec<Rc<Node>>,
    type_: ContainerType,
    layout: Layout,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for Container {

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Weak<Node> {
        self.parent.clone()
        /*
        match self.type_ {
            ContainerType::Root => {
                // such hack
                unsafe {
                    // very unsafe
                    use std::mem;
                    let _dummy: Node = mem::uninitialized();
                    // much dummy
                    let _rc_dummy = Rc::new(_dummy);
                    Rc::downgrade(&_rc_dummy)}
            },
            _ => self.parent.clone(),
        }*/
    }
    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Option<Vec<Weak<Node>>> {
        if self.children.len() == 0 {
            None
        } else {
            Some(self.children.iter().map(|child| Rc::downgrade(&child)).collect())
        }
    }

    fn get_type(&self) -> ContainerType {
        self.type_
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) -> Result<(), &'static str> {
        for child in self.get_children().expect("No children") {
            if let Some(child) = child.upgrade() {
                if let Ok(child) = Rc::try_unwrap(child) {
                    child.remove_container();
                    drop(child);
                }
            }
        }
        Ok(())
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the X (width) and Y (height) dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

}

struct View {
    handle: Option<Box<WlcView>>,
    parent: Weak<Node>,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for View {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Weak<Node> {
        self.parent.clone()
    }

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Option<Vec<Weak<Node>>> {
        None
    }

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType {
        ContainerType::View
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) -> Result<(), &'static str> {
        if let Some(ref handle) = self.handle {
            handle.close();
        }
        drop(self);
        Ok(())
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }
}
<commit_msg>Warning prune<commit_after>//! Layout handling

use rustwlc::handle::{WlcView, WlcOutput};
use std::rc::{Rc, Weak};

pub type Node = Box<Containable>;

#[derive(PartialEq, Clone, Copy)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Types of container
enum ContainerTypes {
    /// Root container, only one exists
    Root,
    /// WlcOutput/monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Layout mode for a container
enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Like i3, everything (workspaces, containers, views) are containable.
pub trait Containable {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Weak<Node>;

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Option<Vec<Weak<Node>>>;

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType;

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool;

    /// Removes this container and all of its children
    fn remove_container(&self) -> Result<(), &'static str>;

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool);

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64);

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64);

    /// Finds a parent container with the given type, if there is any
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<Rc<Node>> {
        let mut container = self.get_parent().upgrade();
        loop {
            if let Some(parent) = container {
                if parent.get_type() == type_ {
                    return Some(parent);
                }
                container = parent.get_parent().upgrade();
            } else {
                return None;
            }
        }
    }
}

/// View specific functions
pub trait Viewable {
    /// Determines if the view is full screen
    fn is_fullscreen(&self) -> bool;

    /// Figures out if the view is focused
    fn is_active(&self) -> bool;

    /// Returns true if this view is a parent is an ancestor of the child
    fn is_parent_of<T: Containable>(&self, child: T) -> bool;

    /// Returns true if this view is a child is an decedent of the parent
    fn is_child_of<T: Containable>(&self, parent: T) -> bool;

    /// Gets the active workspace of the view
    fn active_workspace<T: Containable>(&self) -> T;
}

struct Container {
    handle: Option<WlcOutput>,

    parent: Weak<Node>,
    children: Vec<Rc<Node>>,
    type_: ContainerType,
    layout: Layout,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for Container {

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Weak<Node> {
        self.parent.clone()
        /*
        match self.type_ {
            ContainerType::Root => {
                // such hack
                unsafe {
                    // very unsafe
                    use std::mem;
                    let _dummy: Node = mem::uninitialized();
                    // much dummy
                    let _rc_dummy = Rc::new(_dummy);
                    Rc::downgrade(&_rc_dummy)}
            },
            _ => self.parent.clone(),
        }*/
    }
    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Option<Vec<Weak<Node>>> {
        if self.children.len() == 0 {
            None
        } else {
            Some(self.children.iter().map(|child| Rc::downgrade(&child)).collect())
        }
    }

    fn get_type(&self) -> ContainerType {
        self.type_
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) -> Result<(), &'static str> {
        for child in self.get_children().expect("No children") {
            if let Some(child) = child.upgrade() {
                if let Ok(child) = Rc::try_unwrap(child) {
                    child.remove_container().ok();
                    drop(child);
                }
            }
        }
        Ok(())
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the X (width) and Y (height) dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

}

struct View {
    handle: Option<Box<WlcView>>,
    parent: Weak<Node>,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl Containable for View {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Weak<Node> {
        self.parent.clone()
    }

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Option<Vec<Weak<Node>>> {
        None
    }

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType {
        ContainerType::View
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(&self) -> Result<(), &'static str> {
        if let Some(ref handle) = self.handle {
            handle.close();
        }
        drop(self);
        Ok(())
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }
}
<|endoftext|>