<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::File;
use std::fs::OpenOptions;

use libc::{c_int, ioctl};
use std::default::Default;
use std::io;
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into())
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file with given options.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let mut ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.with().part_scan(true).attach("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn with(&mut self) -> AttachOptions<'_> {
        AttachOptions {
            device: self,
            info: Default::default(),
        }
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let info = LoopInfo64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        let info = LoopInfo64 {
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.2",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        let info = LoopInfo64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    #[deprecated(
        since = "0.2.2",
        note = "use `with().size_limit(size).attach(file)` instead"
    )]
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        size_limit: u64,
    ) -> io::Result<()> {
        let info = LoopInfo64 {
            lo_offset: offset,
            lo_sizelimit: size_limit,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file with loop_info.
    fn attach_with_loop_info(
        &self, // TODO should be mut? - but changing it is a breaking change
        backing_file: impl AsRef<Path>,
        info: LoopInfo64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;

        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD.into(),
                bf.as_raw_fd() as c_int,
            )
        })?;

        if let Err(err) = ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64.into(),
                &info,
            )
        }) {
            // Ignore the error to preserve the original error
            let _ = self.detach();
            return Err(err);
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop7").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe { ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY.into(),
                0,
            )
        })?;
        Ok(())
    }
}

pub struct AttachOptions<'d> {
    device: &'d mut LoopDevice,
    info: LoopInfo64,
}

impl AttachOptions<'_> {
    /// Offset in bytes from the start of the backing file the data will start at.
    pub fn offset(mut self, offset: u64) -> Self {
        self.info.lo_offset = offset;
        self
    }

    /// Maximum size of the data in bytes.
    pub fn size_limit(mut self, size_limit: u64) -> Self {
        self.info.lo_sizelimit = size_limit;
        self
    }

    /// Force the kernel to scan the partition table on a newly created loop device. Note that the
    /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
    pub fn part_scan(mut self, enable: bool) -> Self {
        if enable {
            self.info.lo_flags |= 1 << 4;
        } else {
            self.info.lo_flags &= u32::max_value() - (1 << 4);
        }
        self
    }

    /// Attach the loop device to a file with the set options.
    pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
        self.device.attach_with_loop_info(backing_file, self.info)
    }
}

// https://man7.org/linux/man-pages/man4/loop.4.html
#[repr(C)]
struct LoopInfo64 {
    pub lo_device: u64,           // ioctl r/o
    pub lo_inode: u64,            // ioctl r/o
    pub lo_rdevice: u64,          // ioctl r/o
    pub lo_offset: u64,           //
    pub lo_sizelimit: u64,        // bytes, 0 == max available
    pub lo_number: u32,           // ioctl r/o
    pub lo_encrypt_type: u32,     //
    pub lo_encrypt_key_size: u32, // ioctl w/o
    pub lo_flags: u32,            // ioctl r/w (r/o before Linux 2.6.25)
    pub lo_file_name: [u8; 64],   //
    pub lo_crypt_name: [u8; 64],  //
    pub lo_encrypt_key: [u8; 32], // ioctl w/o
    pub lo_init: [u64; 2],        //
}

impl Default for LoopInfo64 {
    fn default() -> Self {
        Self {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<commit_msg>Adds basic docs for AttachDevice<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.path().unwrap().display());
//!
//! ld.attach_file("test.img").unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::File;
use std::fs::OpenOptions;

use libc::{c_int, ioctl};
use std::default::Default;
use std::io;
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<Self> {
        Ok(Self {
            dev_file: OpenOptions::new()
                .read(true)
                .write(true)
                .open(LOOP_CONTROL)?,
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let dev_num = ioctl_to_error(unsafe {
            ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into())
        })?;
        LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl AsRawFd for LoopDevice {
    fn as_raw_fd(&self) -> RawFd {
        self.device.as_raw_fd()
    }
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        Ok(Self {
            device: OpenOptions::new().read(true).write(true).open(dev)?,
        })
    }

    /// Attach the loop device to a file with given options.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let mut ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.with().part_scan(true).attach("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn with(&mut self) -> AttachOptions<'_> {
        AttachOptions {
            device: self,
            info: Default::default(),
        }
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.0",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
        let info = LoopInfo64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file that maps to the whole file.
    ///
    /// # Examples
    ///
    /// Attach the device to a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach_file("test.img").unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
        let info = LoopInfo64 {
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file.
    #[deprecated(
        since = "0.2.2",
        note = "use `loop.with().offset(offset).attach(file)` instead"
    )]
    pub fn attach_with_offset<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
    ) -> io::Result<()> {
        let info = LoopInfo64 {
            lo_offset: offset,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file starting at offset into the file and a the given sizelimit.
    #[deprecated(
        since = "0.2.2",
        note = "use `with().size_limit(size).attach(file)` instead"
    )]
    pub fn attach_with_sizelimit<P: AsRef<Path>>(
        &self,
        backing_file: P,
        offset: u64,
        size_limit: u64,
    ) -> io::Result<()> {
        let info = LoopInfo64 {
            lo_offset: offset,
            lo_sizelimit: size_limit,
            ..Default::default()
        };

        Self::attach_with_loop_info(self, backing_file, info)
    }

    /// Attach the loop device to a file with loop_info.
    fn attach_with_loop_info(
        &self, // TODO should be mut? - but changing it is a breaking change
        backing_file: impl AsRef<Path>,
        info: LoopInfo64,
    ) -> io::Result<()> {
        let bf = OpenOptions::new()
            .read(true)
            .write(true)
            .open(backing_file)?;

        // Attach the file
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_FD.into(),
                bf.as_raw_fd() as c_int,
            )
        })?;

        if let Err(err) = ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_STATUS64.into(),
                &info,
            )
        }) {
            // Ignore the error to preserve the original error
            let _ = self.detach();
            return Err(err);
        }
        Ok(())
    }

    /// Get the path of the loop device.
    #[deprecated(since = "0.2.0", note = "use `path` instead")]
    pub fn get_path(&self) -> Option<PathBuf> {
        self.path()
    }

    /// Get the path of the loop device.
    pub fn path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// Note that the device won't fully detach until a short delay after the underling device file
    /// gets closed. This happens when LoopDev goes out of scope so you should ensure the LoopDev
    /// lives for a short a time as possible.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop7").unwrap();
    /// # ld.attach_file("test.img").unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        ioctl_to_error(unsafe { ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) })?;
        Ok(())
    }

    /// Resize a live loop device. If the size of the backing file changes this can be called to
    /// inform the loop driver about the new size.
    pub fn set_capacity(&self) -> io::Result<()> {
        ioctl_to_error(unsafe {
            ioctl(
                self.device.as_raw_fd() as c_int,
                LOOP_SET_CAPACITY.into(),
                0,
            )
        })?;
        Ok(())
    }
}

/// Used to set options when attaching a device. Created with [LoopDevice::with()].
pub struct AttachOptions<'d> {
    device: &'d mut LoopDevice,
    info: LoopInfo64,
}

impl AttachOptions<'_> {
    /// Offset in bytes from the start of the backing file the data will start at.
    pub fn offset(mut self, offset: u64) -> Self {
        self.info.lo_offset = offset;
        self
    }

    /// Maximum size of the data in bytes.
    pub fn size_limit(mut self, size_limit: u64) -> Self {
        self.info.lo_sizelimit = size_limit;
        self
    }

    /// Force the kernel to scan the partition table on a newly created loop device. Note that the
    /// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
    pub fn part_scan(mut self, enable: bool) -> Self {
        if enable {
            self.info.lo_flags |= 1 << 4;
        } else {
            self.info.lo_flags &= u32::max_value() - (1 << 4);
        }
        self
    }

    /// Attach the loop device to a file with the set options.
    pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
        self.device.attach_with_loop_info(backing_file, self.info)
    }
}

// https://man7.org/linux/man-pages/man4/loop.4.html
#[repr(C)]
struct LoopInfo64 {
    pub lo_device: u64,           // ioctl r/o
    pub lo_inode: u64,            // ioctl r/o
    pub lo_rdevice: u64,          // ioctl r/o
    pub lo_offset: u64,           //
    pub lo_sizelimit: u64,        // bytes, 0 == max available
    pub lo_number: u32,           // ioctl r/o
    pub lo_encrypt_type: u32,     //
    pub lo_encrypt_key_size: u32, // ioctl w/o
    pub lo_flags: u32,            // ioctl r/w (r/o before Linux 2.6.25)
    pub lo_file_name: [u8; 64],   //
    pub lo_crypt_name: [u8; 64],  //
    pub lo_encrypt_key: [u8; 32], // ioctl w/o
    pub lo_init: [u64; 2],        //
}

impl Default for LoopInfo64 {
    fn default() -> Self {
        Self {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
    if ret < 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use self::rand::Rng;

pub enum WordKind {Adjective, Adverb, Name}
pub enum ListKind {Large, Medium, Small}

pub use self::WordKind::*;
pub use self::ListKind::*;

pub struct WordList<'a> {
    pub wordkind: WordKind,
    pub listkind: ListKind,
    words: Vec<&'a str>,
}

impl<'a> WordList<'a> {

    pub fn load(wordkind: WordKind, listkind: ListKind) -> WordList<'a> {
        let wordlist = match wordkind {
            Adjective => match listkind {
                Large => include_str!("../words/large/adjectives.txt"),
                Medium => include_str!("../words/medium/adjectives.txt"),
                Small => include_str!("../words/small/adjectives.txt"),
            },
            Adverb => match listkind {
                Large => include_str!("../words/large/adverbs.txt"),
                Medium => include_str!("../words/medium/adverbs.txt"),
                Small => include_str!("../words/small/adverbs.txt"),
            },
            Name => match listkind {
                Large => include_str!("../words/large/names.txt"),
                Medium => include_str!("../words/medium/names.txt"),
                Small => include_str!("../words/small/names.txt"),
            },
        };
        WordList{
            wordkind: wordkind, listkind: listkind,
            words: wordlist.split_whitespace().collect(),
        }
    }

    pub fn random(&self) -> &'a str {
        rand::thread_rng().choose(&self.words).unwrap()
    }

    pub fn iter(&self) -> WordListIter {
        WordListIter{wordlist: self, index: 0}
    }

    pub fn iter_random(&self) -> WordListRandomIter {
        WordListRandomIter{wordlist: self}
    }

    pub fn len(&self) -> usize {
        self.words.len()
    }

    pub fn is_empty(&self) -> bool {
        self.words.is_empty()
    }

}

pub struct WordListIter<'a> {
    wordlist: &'a WordList<'a>,
    index: usize,
}

impl<'a> Iterator for WordListIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index < self.wordlist.len() {
            let next = Some(self.wordlist.words[self.index]);
            self.index += 1;
            next
        }
        else {
            None
        }
    }
}

pub struct WordListRandomIter<'a> {
    wordlist: &'a WordList<'a>,
}

impl<'a> Iterator for WordListRandomIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        Some(self.wordlist.random())
    }
}

#[cfg(test)]
mod tests {

    use super::{WordList, WordKind, ListKind};

    #[test]
    fn large_adjectives_is_not_empty() {
        let list = WordList::load(
            WordKind::Adjective, ListKind::Large);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn large_adverbs_is_not_empty() {
        let list = WordList::load(
            WordKind::Adverb, ListKind::Large);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn large_names_is_not_empty() {
        let list = WordList::load(
            WordKind::Name, ListKind::Large);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn medium_adjectives_is_not_empty() {
        let list = WordList::load(
            WordKind::Adjective, ListKind::Medium);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn medium_adverbs_is_not_empty() {
        let list = WordList::load(
            WordKind::Adverb, ListKind::Medium);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn medium_names_is_not_empty() {
        let list = WordList::load(
            WordKind::Name, ListKind::Medium);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn small_adjectives_is_not_empty() {
        let list = WordList::load(
            WordKind::Adjective, ListKind::Small);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn small_adverbs_is_not_empty() {
        let list = WordList::load(
            WordKind::Adverb, ListKind::Small);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn small_names_is_not_empty() {
        let list = WordList::load(
            WordKind::Name, ListKind::Small);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

}
<commit_msg>Iter constructors.<commit_after>extern crate rand;

use self::rand::Rng;

pub enum WordKind {Adjective, Adverb, Name}
pub enum ListKind {Large, Medium, Small}

pub use self::WordKind::*;
pub use self::ListKind::*;

pub struct WordList<'a> {
    pub wordkind: WordKind,
    pub listkind: ListKind,
    words: Vec<&'a str>,
}

impl<'a> WordList<'a> {

    pub fn load(wordkind: WordKind, listkind: ListKind) -> WordList<'a> {
        let wordlist = match wordkind {
            Adjective => match listkind {
                Large => include_str!("../words/large/adjectives.txt"),
                Medium => include_str!("../words/medium/adjectives.txt"),
                Small => include_str!("../words/small/adjectives.txt"),
            },
            Adverb => match listkind {
                Large => include_str!("../words/large/adverbs.txt"),
                Medium => include_str!("../words/medium/adverbs.txt"),
                Small => include_str!("../words/small/adverbs.txt"),
            },
            Name => match listkind {
                Large => include_str!("../words/large/names.txt"),
                Medium => include_str!("../words/medium/names.txt"),
                Small => include_str!("../words/small/names.txt"),
            },
        };
        WordList{
            wordkind: wordkind, listkind: listkind,
            words: wordlist.split_whitespace().collect(),
        }
    }

    pub fn random(&self) -> &'a str {
        rand::thread_rng().choose(&self.words).unwrap()
    }

    pub fn iter(&self) -> WordListIter {
        WordListIter::new(self)
    }

    pub fn iter_random(&self) -> WordListRandomIter {
        WordListRandomIter::new(self)
    }

    pub fn len(&self) -> usize {
        self.words.len()
    }

    pub fn is_empty(&self) -> bool {
        self.words.is_empty()
    }

}

pub struct WordListIter<'a> {
    wordlist: &'a WordList<'a>,
    index: usize,
}

impl<'a> WordListIter<'a> {
    fn new(wordlist: &'a WordList) -> Self {
        Self{wordlist: wordlist, index: 0}
    }
}

impl<'a> Iterator for WordListIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index < self.wordlist.len() {
            let next = Some(self.wordlist.words[self.index]);
            self.index += 1;
            next
        }
        else {
            None
        }
    }
}

pub struct WordListRandomIter<'a> {
    wordlist: &'a WordList<'a>,
}

impl<'a> WordListRandomIter<'a> {
    fn new(wordlist: &'a WordList) -> Self {
        Self{wordlist: wordlist}
    }
}

impl<'a> Iterator for WordListRandomIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        Some(self.wordlist.random())
    }
}

#[cfg(test)]
mod tests {

    use super::{WordList, WordKind, ListKind};

    #[test]
    fn large_adjectives_is_not_empty() {
        let list = WordList::load(
            WordKind::Adjective, ListKind::Large);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn large_adverbs_is_not_empty() {
        let list = WordList::load(
            WordKind::Adverb, ListKind::Large);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn large_names_is_not_empty() {
        let list = WordList::load(
            WordKind::Name, ListKind::Large);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn medium_adjectives_is_not_empty() {
        let list = WordList::load(
            WordKind::Adjective, ListKind::Medium);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn medium_adverbs_is_not_empty() {
        let list = WordList::load(
            WordKind::Adverb, ListKind::Medium);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn medium_names_is_not_empty() {
        let list = WordList::load(
            WordKind::Name, ListKind::Medium);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn small_adjectives_is_not_empty() {
        let list = WordList::load(
            WordKind::Adjective, ListKind::Small);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn small_adverbs_is_not_empty() {
        let list = WordList::load(
            WordKind::Adverb, ListKind::Small);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

    #[test]
    fn small_names_is_not_empty() {
        let list = WordList::load(
            WordKind::Name, ListKind::Small);
        assert_ne!(list.len(), 0);
        assert!(!list.is_empty());
    }

}
<|endoftext|>


<commit_before>extern crate rand;
extern crate rustc_serialize;

/// Width of game board
#[cfg(not(test))] pub const WIDTH: usize = 8;
#[cfg(test)]      pub const WIDTH: usize = 3;
/// Height of game board
#[cfg(not(test))] pub const HEIGHT: usize = 8;
#[cfg(test)]      pub const HEIGHT: usize = 3;
/// Number of rows
#[cfg(not(test))] pub const ROWS: usize = 2;
#[cfg(test)]      pub const ROWS: usize = 1;

const RED: Player = Player::Red;
const BLUE: Player = Player::Blue;

const ROCK: RPS = RPS::Rock;
const PAPER: RPS = RPS::Paper;
const SCISSORS: RPS = RPS::Scissors;

const WIN: Outcome = Outcome::Win;
const LOSE: Outcome = Outcome::Lose;
const DRAW: Outcome = Outcome::Draw;

pub mod moves;
pub mod win_conditions;
pub mod unit;
pub mod field;

use moves::{is_valid, Move};
use win_conditions::{WinCondition};
use field::{Field, PovField};
use unit::{Unit, GeneralUnit};

use std::marker::PhantomData;

#[derive(Clone, Debug)]
pub struct Game<T: WinCondition<GeneralUnit>> {
    turns: u32,
    current_turn: Player,
    winner: Option<Player>,
    field: Field<GeneralUnit>,
    rules: Rules<GeneralUnit, T>,
}

impl<T: WinCondition<GeneralUnit>> Game<T> {
    pub fn new(rules: Rules<GeneralUnit, T>) -> Game<T> {
        let mut rows = [[None; WIDTH]; HEIGHT];
        for i in 0..ROWS {
            rows[i] = [Some(RED.random_unit()); WIDTH];
            rows[HEIGHT - i - 1] = [Some(BLUE.random_unit()); WIDTH];
        }
        let field = Field { rows: rows };
        Game {
            turns: 1,
            current_turn: RED,
            winner: None,
            field: field,
            rules: rules,
        }
    }

    pub fn turns(&self) -> u32 { self.turns }
    pub fn current_turn(&self) -> Player { self.current_turn }
    pub fn winner(&self) -> Option<Player> { self.winner }
    pub fn field(&self) -> &Field<GeneralUnit> { &self.field }

    pub fn force_win(&mut self, player: Player) {
        if !self.winner.is_some() { self.winner = Some(player); }
    }

    pub fn perspective(&self, player: Player) -> PovField {
        PovField::from((&self.field, player))
    }

    pub fn make_move(&mut self, movement: Move) -> Result<Option<Outcome>, MoveError> {
        if self.winner.is_some() { return Err(MoveError::GameAlreadyFinished); }

        if !is_valid(movement) {
            return Err(MoveError::DeclinedByMoveCondition);
        }

        let (from_x, from_y) = movement.from;

        if from_x >= WIDTH || from_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

        let attack_outcome;
        let (to_x, to_y);

        if let Some(ref unit) = self.field.rows[from_y][from_x].as_ref() {
            if unit.owner != self.current_turn { return Err(MoveError::WrongOwner); }
            let dist = movement.apply(unit.owner);
            to_x = dist.0;
            to_y = dist.1;
            if to_x >= WIDTH || to_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

            if let Some(ref defender) = self.field.rows[to_y][to_x].as_ref() {
                if defender.owner == self.current_turn { return Err(MoveError::SameOwner); }

                match unit.attack(defender) {
                    Some(res) => {
                        attack_outcome = Some(res);
                    },
                    None => { return Err(MoveError::UnexpextedError); }
                }
            } else {
                attack_outcome = None;
            }

        } else {
            return Err(MoveError::NoUnitInPosition);
        }

        if let Some(outcome) = attack_outcome {
            match outcome {
                WIN => {
                    self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                LOSE => {
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                DRAW => {
                    let v1 = self.field.rows[from_y][from_x].as_mut().unwrap().visible;
                    let v2 = self.field.rows[to_y][to_x].as_mut().unwrap().visible;

                    if v1 && v2{
                        self.field.rows[from_y][from_x].as_mut().unwrap().rps = RPS::random();
                        self.field.rows[to_y][to_x].as_mut().unwrap().rps = RPS::random();
                    } else {
                        self.field.rows[from_y][from_x].as_mut().unwrap().visible = true;
                        self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                    }
                }
            }
        } else {
            self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
            self.field.rows[from_y][from_x] = None;
        }

        self.winner = self.rules.win_condition.winner(&self.field);
        self.turns += 1;
        self.current_turn = self.current_turn.next();

        Ok(attack_outcome)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MoveError {
    GameAlreadyFinished,
    DeclinedByMoveCondition,
    PositionOutOfBounds,
    WrongOwner,
    NoUnitInPosition,
    SameOwner,
    UnexpextedError,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum Player {
    Red,
    Blue,
}

impl Player {
    fn next(&self) -> Player {
        match *self {
            RED => BLUE,
            BLUE => RED,
        }
    }

    fn unit(&self, rps: RPS) -> GeneralUnit {
        GeneralUnit::new(rps, *self)
    }

    fn random_unit(&self) -> GeneralUnit {
        self.unit(RPS::random())
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum RPS {
    Rock,
    Paper,
    Scissors,
}

impl RPS {
    fn attack(&self, opponent: RPS) -> Outcome {
        match (*self, opponent) {
            (PAPER, ROCK) | (ROCK, SCISSORS) | (SCISSORS, PAPER) => WIN,
            (ROCK, PAPER) | (SCISSORS, ROCK) | (PAPER, SCISSORS) => LOSE,
            _ => DRAW,
        }
    }

    fn random() -> RPS {
        match rand::random::<usize>() % 3 {
            0 => ROCK,
            1 => PAPER,
            2 => SCISSORS,
            _ => { panic!("rand::random::<usize>() % 3 returned not 0, nor 1, nor 2"); }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Outcome {
    Win,
    Lose,
    Draw,
}

#[derive(Clone, Debug)]
pub struct Rules<K, T: WinCondition<K>> where K: Unit {
    pub win_condition: T,
    phantom_data: PhantomData<K>,
}

impl<K: Unit, T: WinCondition<K>> Rules<K, T> {
    pub fn new(win_condition: T) -> Rules<K, T> {
        Rules {
            win_condition: win_condition,
            phantom_data: PhantomData,
        }
    }
}

#[test]
fn basic_test() {
    use moves::{Direction};
    use win_conditions::EliminateCondition;

    let rules = Rules::new(EliminateCondition);
    let mut game = Game::new(rules);
    let move1 = Move::new(0, 0, Direction::Forward);

    assert_eq!(game.make_move(move1), Ok(None));

    assert_eq!(game.make_move(move1), Err(MoveError::NoUnitInPosition));

    let move2 = Move::new(0, 2, Direction::Forward);
    assert!(game.make_move(move2).unwrap().is_some());
}
<commit_msg>use statements moved<commit_after>extern crate rand;
extern crate rustc_serialize;

/// Width of game board
#[cfg(not(test))] pub const WIDTH: usize = 8;
#[cfg(test)]      pub const WIDTH: usize = 3;
/// Height of game board
#[cfg(not(test))] pub const HEIGHT: usize = 8;
#[cfg(test)]      pub const HEIGHT: usize = 3;
/// Number of rows
#[cfg(not(test))] pub const ROWS: usize = 2;
#[cfg(test)]      pub const ROWS: usize = 1;

const RED: Player = Player::Red;
const BLUE: Player = Player::Blue;

const ROCK: RPS = RPS::Rock;
const PAPER: RPS = RPS::Paper;
const SCISSORS: RPS = RPS::Scissors;

const WIN: Outcome = Outcome::Win;
const LOSE: Outcome = Outcome::Lose;
const DRAW: Outcome = Outcome::Draw;

use std::marker::PhantomData;

use moves::{is_valid, Move};
use win_conditions::{WinCondition};
use field::{Field, PovField};
use unit::{Unit, GeneralUnit};

pub mod moves;
pub mod win_conditions;
pub mod unit;
pub mod field;

#[derive(Clone, Debug)]
pub struct Game<T: WinCondition<GeneralUnit>> {
    turns: u32,
    current_turn: Player,
    winner: Option<Player>,
    field: Field<GeneralUnit>,
    rules: Rules<GeneralUnit, T>,
}

impl<T: WinCondition<GeneralUnit>> Game<T> {
    pub fn new(rules: Rules<GeneralUnit, T>) -> Game<T> {
        let mut rows = [[None; WIDTH]; HEIGHT];
        for i in 0..ROWS {
            rows[i] = [Some(RED.random_unit()); WIDTH];
            rows[HEIGHT - i - 1] = [Some(BLUE.random_unit()); WIDTH];
        }
        let field = Field { rows: rows };
        Game {
            turns: 1,
            current_turn: RED,
            winner: None,
            field: field,
            rules: rules,
        }
    }

    pub fn turns(&self) -> u32 { self.turns }
    pub fn current_turn(&self) -> Player { self.current_turn }
    pub fn winner(&self) -> Option<Player> { self.winner }
    pub fn field(&self) -> &Field<GeneralUnit> { &self.field }

    pub fn force_win(&mut self, player: Player) {
        if !self.winner.is_some() { self.winner = Some(player); }
    }

    pub fn perspective(&self, player: Player) -> PovField {
        PovField::from((&self.field, player))
    }

    pub fn make_move(&mut self, movement: Move) -> Result<Option<Outcome>, MoveError> {
        if self.winner.is_some() { return Err(MoveError::GameAlreadyFinished); }

        if !is_valid(movement) {
            return Err(MoveError::DeclinedByMoveCondition);
        }

        let (from_x, from_y) = movement.from;

        if from_x >= WIDTH || from_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

        let attack_outcome;
        let (to_x, to_y);

        if let Some(ref unit) = self.field.rows[from_y][from_x].as_ref() {
            if unit.owner != self.current_turn { return Err(MoveError::WrongOwner); }
            let dist = movement.apply(unit.owner);
            to_x = dist.0;
            to_y = dist.1;
            if to_x >= WIDTH || to_y >= HEIGHT { return Err(MoveError::PositionOutOfBounds); }

            if let Some(ref defender) = self.field.rows[to_y][to_x].as_ref() {
                if defender.owner == self.current_turn { return Err(MoveError::SameOwner); }

                match unit.attack(defender) {
                    Some(res) => {
                        attack_outcome = Some(res);
                    },
                    None => { return Err(MoveError::UnexpextedError); }
                }
            } else {
                attack_outcome = None;
            }

        } else {
            return Err(MoveError::NoUnitInPosition);
        }

        if let Some(outcome) = attack_outcome {
            match outcome {
                WIN => {
                    self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                LOSE => {
                    self.field.rows[from_y][from_x] = None;
                    self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                },
                DRAW => {
                    let v1 = self.field.rows[from_y][from_x].as_mut().unwrap().visible;
                    let v2 = self.field.rows[to_y][to_x].as_mut().unwrap().visible;

                    if v1 && v2{
                        self.field.rows[from_y][from_x].as_mut().unwrap().rps = RPS::random();
                        self.field.rows[to_y][to_x].as_mut().unwrap().rps = RPS::random();
                    } else {
                        self.field.rows[from_y][from_x].as_mut().unwrap().visible = true;
                        self.field.rows[to_y][to_x].as_mut().unwrap().visible = true;
                    }
                }
            }
        } else {
            self.field.rows[to_y][to_x] = self.field.rows[from_y][from_x];
            self.field.rows[from_y][from_x] = None;
        }

        self.winner = self.rules.win_condition.winner(&self.field);
        self.turns += 1;
        self.current_turn = self.current_turn.next();

        Ok(attack_outcome)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MoveError {
    GameAlreadyFinished,
    DeclinedByMoveCondition,
    PositionOutOfBounds,
    WrongOwner,
    NoUnitInPosition,
    SameOwner,
    UnexpextedError,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum Player {
    Red,
    Blue,
}

impl Player {
    fn next(&self) -> Player {
        match *self {
            RED => BLUE,
            BLUE => RED,
        }
    }

    fn unit(&self, rps: RPS) -> GeneralUnit {
        GeneralUnit::new(rps, *self)
    }

    fn random_unit(&self) -> GeneralUnit {
        self.unit(RPS::random())
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum RPS {
    Rock,
    Paper,
    Scissors,
}

impl RPS {
    fn attack(&self, opponent: RPS) -> Outcome {
        match (*self, opponent) {
            (PAPER, ROCK) | (ROCK, SCISSORS) | (SCISSORS, PAPER) => WIN,
            (ROCK, PAPER) | (SCISSORS, ROCK) | (PAPER, SCISSORS) => LOSE,
            _ => DRAW,
        }
    }

    fn random() -> RPS {
        match rand::random::<usize>() % 3 {
            0 => ROCK,
            1 => PAPER,
            2 => SCISSORS,
            _ => { panic!("rand::random::<usize>() % 3 returned not 0, nor 1, nor 2"); }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Outcome {
    Win,
    Lose,
    Draw,
}

#[derive(Clone, Debug)]
pub struct Rules<K, T: WinCondition<K>> where K: Unit {
    pub win_condition: T,
    phantom_data: PhantomData<K>,
}

impl<K: Unit, T: WinCondition<K>> Rules<K, T> {
    pub fn new(win_condition: T) -> Rules<K, T> {
        Rules {
            win_condition: win_condition,
            phantom_data: PhantomData,
        }
    }
}

#[test]
fn basic_test() {
    use moves::{Direction};
    use win_conditions::EliminateCondition;

    let rules = Rules::new(EliminateCondition);
    let mut game = Game::new(rules);
    let move1 = Move::new(0, 0, Direction::Forward);

    assert_eq!(game.make_move(move1), Ok(None));

    assert_eq!(game.make_move(move1), Err(MoveError::NoUnitInPosition));

    let move2 = Move::new(0, 2, Direction::Forward);
    assert!(game.make_move(move2).unwrap().is_some());
}
<|endoftext|>


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

// Running external documentation tests depends on the
// `external_doc` unstable feature only available on a
// nightly compiler. So we enable the feature only when needed.
#![cfg_attr(doctest, feature(external_doc))]

mod cluster;
pub mod config;
pub mod extensions;
pub(crate) mod metrics;
pub mod proxy;
pub mod runner;
pub mod test_utils;
pub(crate) mod utils;
pub(crate) mod xds;

#[cfg(doctest)]
pub mod external_doc_tests {
    // Run tests in our external documentation.
    // Because this depends on the `external_doc` unstable feature,
    // it is only available using a nightly compiler.
    // To run them locally run e.g `cargo +nightly test --doc`
    #![doc(include = "../docs/extensions/filters/filters.md")]
    #![doc(include = "../docs/extensions/filters/writing_custom_filters.md")]
    #![doc(include = "../docs/extensions/filters/load_balancer.md")]
    #![doc(include = "../docs/extensions/filters/local_rate_limit.md")]
    #![doc(include = "../docs/extensions/filters/debug.md")]
    #![doc(include = "../docs/extensions/filters/concatenate_bytes.md")]
    #![doc(include = "../docs/extensions/filters/capture_bytes.md")]
    #![doc(include = "../docs/extensions/filters/token_router.md")]
    #![doc(include = "../docs/extensions/filters/compress.md")]
}
<commit_msg>Use include_str! instead of doc(include) (#284)<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

mod cluster;
pub mod config;
pub mod extensions;
pub(crate) mod metrics;
pub mod proxy;
pub mod runner;
pub mod test_utils;
pub(crate) mod utils;
pub(crate) mod xds;

/// Run tests in our external documentation. This is only available in
/// nightly at the moment, but is stable on nightly and will be available in
/// 1.54.0. To run them locally run e.g `cargo +nightly test --doc`.
#[cfg(doctest)]
mod external_doc_tests {
    // HACK(XAMPPRocky): This is hidden inside a macro, because the right hand
    // side of `include_str!` is parsed before the `cfg` predicate currently.
    // https://github.com/rust-lang/rust/issues/85882
    macro_rules! hide {
        () => {
            #[doc = include_str!("../docs/extensions/filters/filters.md")]
            #[doc = include_str!("../docs/extensions/filters/writing_custom_filters.md")]
            #[doc = include_str!("../docs/extensions/filters/load_balancer.md")]
            #[doc = include_str!("../docs/extensions/filters/local_rate_limit.md")]
            #[doc = include_str!("../docs/extensions/filters/debug.md")]
            #[doc = include_str!("../docs/extensions/filters/concatenate_bytes.md")]
            #[doc = include_str!("../docs/extensions/filters/capture_bytes.md")]
            #[doc = include_str!("../docs/extensions/filters/token_router.md")]
            #[doc = include_str!("../docs/extensions/filters/compress.md")]
            mod tests {}
        };
    }

    hide!();
}
<|endoftext|>


<commit_before>#![feature(zero_one)]

extern crate openblas;

use linalg::{Transpose};

use openblas::ffi::*;

use std::num::{Zero};

pub mod linalg;

pub trait ArrayIndex: Copy {
  fn least_stride(&self) -> Self;
  fn flat_len(&self) -> usize;
  fn offset(&self, stride: Self) -> usize;
  fn diff(&self, rhs: Self) -> Self;

  /*fn major_iter(self) -> MajorIter<Self> where Self: Default {
    MajorIter{
      idx:          Default::default(),
      upper_bound:  self,
    }
  }*/
}

impl ArrayIndex for usize {
  fn least_stride(&self) -> Self {
    1
  }

  fn flat_len(&self) -> usize {
    *self
  }

  fn offset(&self, stride: Self) -> usize {
    *self * stride
  }

  fn diff(&self, rhs: Self) -> Self {
    *self - rhs
  }
}

impl ArrayIndex for (usize, usize) {
  fn least_stride(&self) -> Self {
    (1, self.0)
  }

  fn flat_len(&self) -> usize {
    self.0 * self.1
  }

  fn offset(&self, stride: Self) -> usize {
    //stride.0 * (self.0 + stride.1 * self.1)
    stride.0 * self.0 + stride.1 * self.1
  }

  fn diff(&self, rhs: Self) -> Self {
    (self.0 - rhs.0, self.1 - rhs.1)
  }
}

impl ArrayIndex for (usize, usize, usize) {
  fn least_stride(&self) -> Self {
    (1, self.0, self.0 * self.1)
  }

  fn flat_len(&self) -> usize {
    self.0 * self.1 * self.2
  }

  fn offset(&self, stride: Self) -> usize {
    //stride.0 * (self.0 + stride.1 * (self.1 + stride.2 * self.2))
    stride.0 * self.0 + stride.1 * self.1 + stride.2 * self.2
  }

  fn diff(&self, rhs: Self) -> Self {
    (self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
  }
}

pub trait Reshape<'a, Idx, Target> where Idx: ArrayIndex {
  fn reshape(&'a self, dim: Idx) -> Target;
  fn reshape_stride(&'a self, dim: Idx, stride: Idx) -> Target { unimplemented!(); }
}

pub trait ReshapeMut<'a, Idx, Target> where Idx: ArrayIndex {
  fn reshape_mut(&'a mut self, dim: Idx) -> Target;
  fn reshape_mut_stride(&'a mut self, dim: Idx, stride: Idx) -> Target { unimplemented!(); }
}

pub trait View<'a, Idx, Target> where Idx: ArrayIndex {
  fn view(&'a self, lo: Idx, hi: Idx) -> Target;
}

pub trait ViewMut<'a, Idx, Target> where Idx: ArrayIndex {
  fn view_mut(&'a mut self, lo: Idx, hi: Idx) -> Target;
}

pub trait AsView<'a, Target> {
  fn as_view(&'a self) -> Target;
}

pub trait AsViewMut<'a, Target> {
  fn as_view_mut(&'a mut self) -> Target;
}

impl<'a, T> Reshape<'a, (usize, usize), Array2dView<'a, T>> for [T] where T: Copy {
  fn reshape(&'a self, dim: (usize, usize)) -> Array2dView<'a, T> {
    // Assume unit stride.
    Array2dView{
      data_buf: self,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

impl<'a, T> ReshapeMut<'a, (usize, usize), Array2dViewMut<'a, T>> for [T] where T: Copy {
  fn reshape_mut(&'a mut self, dim: (usize, usize)) -> Array2dViewMut<'a, T> {
    // Assume unit stride.
    Array2dViewMut{
      data_buf: self,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

pub struct Array1d<T> where T: Copy {
  data_buf: Vec<T>,
  dim:      usize,
  stride:   usize,
}

/*pub struct Array1d<T, S=Vec<T>> where T: Copy, S: Storage<T> {
  data_buf: S,
  dim:      usize,
  stride:   usize,
}*/

impl<T> Array1d<T> where T: Copy + Zero {
  pub fn zeros(dim: usize) -> Array1d<T> {
    let len = dim.flat_len();
    let mut data = Vec::with_capacity(len);
    unsafe { data.set_len(len) };
    for i in 0 .. len {
      data[i] = T::zero();
    }
    Array1d{
      data_buf: data,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

impl<T> Array1d<T> where T: Copy {
}

pub struct Array2d<T> where T: Copy {
  data_buf: Vec<T>,
  dim:      (usize, usize),
  stride:   (usize, usize),
}

impl<T> Array2d<T> where T: Copy + Zero {
  pub fn zeros(dim: (usize, usize)) -> Array2d<T> {
    let len = dim.flat_len();
    let mut data = Vec::with_capacity(len);
    unsafe { data.set_len(len) };
    for i in 0 .. len {
      data[i] = T::zero();
    }
    Array2d{
      data_buf: data,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

impl<T> Array2d<T> where T: Copy {
}

impl<'a, T> AsView<'a, Array2dView<'a, T>> for Array2d<T> where T: Copy {
  fn as_view(&'a self) -> Array2dView<'a, T> {
    Array2dView{
      data_buf: &self.data_buf,
      dim:      self.dim,
      stride:   self.stride,
    }
  }
}

impl<'a, T> AsViewMut<'a, Array2dViewMut<'a, T>> for Array2d<T> where T: Copy {
  fn as_view_mut(&'a mut self) -> Array2dViewMut<'a, T> {
    Array2dViewMut{
      data_buf: &mut self.data_buf,
      dim:      self.dim,
      stride:   self.stride,
    }
  }
}

pub struct Array2dView<'a, T> where T: 'a + Copy {
  data_buf: &'a [T],
  dim:      (usize, usize),
  stride:   (usize, usize),
}

impl<'a> Array2dView<'a, f32> {
  pub fn dim(&self) -> (usize, usize) {
    self.dim
  }

  pub fn stride(&self) -> (usize, usize) {
    self.stride
  }
}

impl<'a, T> View<'a, (usize, usize), Array2dView<'a, T>> for Array2dView<'a, T> where T: 'a + Copy {
  fn view(&'a self, lo: (usize, usize), hi: (usize, usize)) -> Array2dView<'a, T> {
    let lo_offset = lo.offset(self.stride);
    let hi_offset = hi.offset(self.stride);
    let new_dim = hi.diff(lo);
    Array2dView{
      data_buf: &self.data_buf[lo_offset .. hi_offset],
      dim:      new_dim,
      stride:   self.stride,
    }
  }
}

pub struct Array2dViewMut<'a, T> where T: 'a + Copy {
  data_buf: &'a mut [T],
  dim:      (usize, usize),
  stride:   (usize, usize),
}

impl<'a, T> ViewMut<'a, (usize, usize), Array2dViewMut<'a, T>> for Array2dViewMut<'a, T> where T: 'a + Copy {
  fn view_mut(&'a mut self, lo: (usize, usize), hi: (usize, usize)) -> Array2dViewMut<'a, T> {
    let lo_offset = lo.offset(self.stride);
    let hi_offset = hi.offset(self.stride);
    let new_dim = hi.diff(lo);
    Array2dViewMut{
      data_buf: &mut self.data_buf[lo_offset .. hi_offset],
      dim:      new_dim,
      stride:   self.stride,
    }
  }
}

impl<'a> Array2dViewMut<'a, f32> {
  pub fn dim(&self) -> (usize, usize) {
    self.dim
  }

  pub fn stride(&self) -> (usize, usize) {
    self.stride
  }

  pub fn set_constant(&'a mut self, alpha: f32) {
    for i in 0 .. self.dim.flat_len() {
      self.data_buf[i] = alpha;
    }
  }

  pub fn matrix_sum(&'a mut self, alpha: f32, x: Array2dView<'a, f32>) {
    let (x_m, x_n) = x.dim();
    let (y_m, y_n) = self.dim();
    assert_eq!(x_m, y_m);
    assert_eq!(x_n, y_n);
    let (incx, ldx) = x.stride();
    let (incy, ldy) = self.stride();
    if x_n == 1 {
      unsafe { cblas_saxpy(
          x_m as _,
          alpha,
          x.data_buf.as_ptr(),
          incx as _,
          self.data_buf.as_mut_ptr(),
          incy as _,
      ) };
    } else if x_m == 1 {
      unimplemented!();
    } else {
      unimplemented!();
    }
  }

  pub fn matrix_prod(&'a mut self, alpha: f32, a: Array2dView<'a, f32>, a_trans: Transpose, b: Array2dView<'a, f32>, b_trans: Transpose, beta: f32) {
    let (a_m, a_n) = a.dim();
    let (b_m, b_n) = b.dim();
    let (c_m, c_n) = self.dim();
    let k = match (a_trans, b_trans) {
      (Transpose::N, Transpose::N) => {
        assert_eq!(c_m, a_m);
        assert_eq!(c_n, b_n);
        assert_eq!(a_n, b_m);
        a_n
      }
      (Transpose::T, Transpose::N) => {
        assert_eq!(c_m, a_n);
        assert_eq!(c_n, b_n);
        assert_eq!(a_m, b_m);
        a_m
      }
      (Transpose::N, Transpose::T) => {
        assert_eq!(c_m, a_m);
        assert_eq!(c_n, b_m);
        assert_eq!(a_n, b_n);
        a_n
      }
      (Transpose::T, Transpose::T) => {
        assert_eq!(c_m, a_n);
        assert_eq!(c_n, b_m);
        assert_eq!(a_m, b_n);
        a_m
      }
    };
    let (a_s0, lda) = a.stride();
    let (b_s0, ldb) = b.stride();
    let (c_s0, ldc) = self.stride();
    assert_eq!(1, a_s0);
    assert_eq!(1, b_s0);
    assert_eq!(1, c_s0);
    unsafe { cblas_sgemm(
        CblasOrder::ColMajor,
        match a_trans {
          Transpose::N => CblasTranspose::NoTrans,
          Transpose::T => CblasTranspose::Trans,
        },
        match b_trans {
          Transpose::N => CblasTranspose::NoTrans,
          Transpose::T => CblasTranspose::Trans,
        },
        c_m as _, c_n as _, k as _,
        alpha,
        a.data_buf.as_ptr(),
        lda as _,
        b.data_buf.as_ptr(),
        ldb as _,
        beta,
        self.data_buf.as_mut_ptr(),
        ldc as _,
    ) };
  }
}

impl<'a> Array2dViewMut<'a, f64> {
  pub fn matrix_prod(&'a mut self) {
    unimplemented!();
  }
}
<commit_msg>Accessing underlying storage of an array as a slice.<commit_after>#![feature(zero_one)]

extern crate openblas;

use linalg::{Transpose};

use openblas::ffi::*;

use std::num::{Zero};

pub mod linalg;

pub trait ArrayIndex: Copy {
  fn least_stride(&self) -> Self;
  fn flat_len(&self) -> usize;
  fn offset(&self, stride: Self) -> usize;
  fn diff(&self, rhs: Self) -> Self;

  /*fn major_iter(self) -> MajorIter<Self> where Self: Default {
    MajorIter{
      idx:          Default::default(),
      upper_bound:  self,
    }
  }*/
}

impl ArrayIndex for usize {
  fn least_stride(&self) -> Self {
    1
  }

  fn flat_len(&self) -> usize {
    *self
  }

  fn offset(&self, stride: Self) -> usize {
    *self * stride
  }

  fn diff(&self, rhs: Self) -> Self {
    *self - rhs
  }
}

impl ArrayIndex for (usize, usize) {
  fn least_stride(&self) -> Self {
    (1, self.0)
  }

  fn flat_len(&self) -> usize {
    self.0 * self.1
  }

  fn offset(&self, stride: Self) -> usize {
    //stride.0 * (self.0 + stride.1 * self.1)
    stride.0 * self.0 + stride.1 * self.1
  }

  fn diff(&self, rhs: Self) -> Self {
    (self.0 - rhs.0, self.1 - rhs.1)
  }
}

impl ArrayIndex for (usize, usize, usize) {
  fn least_stride(&self) -> Self {
    (1, self.0, self.0 * self.1)
  }

  fn flat_len(&self) -> usize {
    self.0 * self.1 * self.2
  }

  fn offset(&self, stride: Self) -> usize {
    //stride.0 * (self.0 + stride.1 * (self.1 + stride.2 * self.2))
    stride.0 * self.0 + stride.1 * self.1 + stride.2 * self.2
  }

  fn diff(&self, rhs: Self) -> Self {
    (self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
  }
}

pub trait Reshape<'a, Idx, Target> where Idx: ArrayIndex {
  fn reshape(&'a self, dim: Idx) -> Target;
  fn reshape_stride(&'a self, dim: Idx, stride: Idx) -> Target { unimplemented!(); }
}

pub trait ReshapeMut<'a, Idx, Target> where Idx: ArrayIndex {
  fn reshape_mut(&'a mut self, dim: Idx) -> Target;
  fn reshape_mut_stride(&'a mut self, dim: Idx, stride: Idx) -> Target { unimplemented!(); }
}

pub trait View<'a, Idx, Target> where Idx: ArrayIndex {
  fn view(&'a self, lo: Idx, hi: Idx) -> Target;
}

pub trait ViewMut<'a, Idx, Target> where Idx: ArrayIndex {
  fn view_mut(&'a mut self, lo: Idx, hi: Idx) -> Target;
}

pub trait AsView<'a, Target> {
  fn as_view(&'a self) -> Target;
}

pub trait AsViewMut<'a, Target> {
  fn as_view_mut(&'a mut self) -> Target;
}

impl<'a, T> Reshape<'a, (usize, usize), Array2dView<'a, T>> for [T] where T: Copy {
  fn reshape(&'a self, dim: (usize, usize)) -> Array2dView<'a, T> {
    // Assume unit stride.
    Array2dView{
      data_buf: self,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

impl<'a, T> ReshapeMut<'a, (usize, usize), Array2dViewMut<'a, T>> for [T] where T: Copy {
  fn reshape_mut(&'a mut self, dim: (usize, usize)) -> Array2dViewMut<'a, T> {
    // Assume unit stride.
    Array2dViewMut{
      data_buf: self,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

pub struct Array1d<T> where T: Copy {
  data_buf: Vec<T>,
  dim:      usize,
  stride:   usize,
}

/*pub struct Array1d<T, S=Vec<T>> where T: Copy, S: Storage<T> {
  data_buf: S,
  dim:      usize,
  stride:   usize,
}*/

impl<T> Array1d<T> where T: Copy + Zero {
  pub fn zeros(dim: usize) -> Array1d<T> {
    let len = dim.flat_len();
    let mut data = Vec::with_capacity(len);
    unsafe { data.set_len(len) };
    for i in 0 .. len {
      data[i] = T::zero();
    }
    Array1d{
      data_buf: data,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

impl<T> Array1d<T> where T: Copy {
}

pub struct Array2d<T> where T: Copy {
  data_buf: Vec<T>,
  dim:      (usize, usize),
  stride:   (usize, usize),
}

impl<T> Array2d<T> where T: Copy + Zero {
  pub fn zeros(dim: (usize, usize)) -> Array2d<T> {
    let len = dim.flat_len();
    let mut data = Vec::with_capacity(len);
    unsafe { data.set_len(len) };
    for i in 0 .. len {
      data[i] = T::zero();
    }
    Array2d{
      data_buf: data,
      dim:      dim,
      stride:   dim.least_stride(),
    }
  }
}

impl<T> Array2d<T> where T: Copy {
  pub fn as_mut_slice(&mut self) -> &mut [T] {
    &mut self.data_buf
  }
}

impl<'a, T> AsView<'a, Array2dView<'a, T>> for Array2d<T> where T: Copy {
  fn as_view(&'a self) -> Array2dView<'a, T> {
    Array2dView{
      data_buf: &self.data_buf,
      dim:      self.dim,
      stride:   self.stride,
    }
  }
}

impl<'a, T> AsViewMut<'a, Array2dViewMut<'a, T>> for Array2d<T> where T: Copy {
  fn as_view_mut(&'a mut self) -> Array2dViewMut<'a, T> {
    Array2dViewMut{
      data_buf: &mut self.data_buf,
      dim:      self.dim,
      stride:   self.stride,
    }
  }
}

pub struct Array2dView<'a, T> where T: 'a + Copy {
  data_buf: &'a [T],
  dim:      (usize, usize),
  stride:   (usize, usize),
}

impl<'a> Array2dView<'a, f32> {
  pub fn dim(&self) -> (usize, usize) {
    self.dim
  }

  pub fn stride(&self) -> (usize, usize) {
    self.stride
  }
}

impl<'a, T> View<'a, (usize, usize), Array2dView<'a, T>> for Array2dView<'a, T> where T: 'a + Copy {
  fn view(&'a self, lo: (usize, usize), hi: (usize, usize)) -> Array2dView<'a, T> {
    let lo_offset = lo.offset(self.stride);
    let hi_offset = hi.offset(self.stride);
    let new_dim = hi.diff(lo);
    Array2dView{
      data_buf: &self.data_buf[lo_offset .. hi_offset],
      dim:      new_dim,
      stride:   self.stride,
    }
  }
}

pub struct Array2dViewMut<'a, T> where T: 'a + Copy {
  data_buf: &'a mut [T],
  dim:      (usize, usize),
  stride:   (usize, usize),
}

impl<'a, T> ViewMut<'a, (usize, usize), Array2dViewMut<'a, T>> for Array2dViewMut<'a, T> where T: 'a + Copy {
  fn view_mut(&'a mut self, lo: (usize, usize), hi: (usize, usize)) -> Array2dViewMut<'a, T> {
    let lo_offset = lo.offset(self.stride);
    let hi_offset = hi.offset(self.stride);
    let new_dim = hi.diff(lo);
    Array2dViewMut{
      data_buf: &mut self.data_buf[lo_offset .. hi_offset],
      dim:      new_dim,
      stride:   self.stride,
    }
  }
}

impl<'a> Array2dViewMut<'a, f32> {
  pub fn dim(&self) -> (usize, usize) {
    self.dim
  }

  pub fn stride(&self) -> (usize, usize) {
    self.stride
  }

  pub fn set_constant(&'a mut self, alpha: f32) {
    for i in 0 .. self.dim.flat_len() {
      self.data_buf[i] = alpha;
    }
  }

  pub fn matrix_sum(&'a mut self, alpha: f32, x: Array2dView<'a, f32>) {
    let (x_m, x_n) = x.dim();
    let (y_m, y_n) = self.dim();
    assert_eq!(x_m, y_m);
    assert_eq!(x_n, y_n);
    let (incx, ldx) = x.stride();
    let (incy, ldy) = self.stride();
    if x_n == 1 {
      unsafe { cblas_saxpy(
          x_m as _,
          alpha,
          x.data_buf.as_ptr(),
          incx as _,
          self.data_buf.as_mut_ptr(),
          incy as _,
      ) };
    } else if x_m == 1 {
      unimplemented!();
    } else {
      unimplemented!();
    }
  }

  pub fn matrix_prod(&'a mut self, alpha: f32, a: Array2dView<'a, f32>, a_trans: Transpose, b: Array2dView<'a, f32>, b_trans: Transpose, beta: f32) {
    let (a_m, a_n) = a.dim();
    let (b_m, b_n) = b.dim();
    let (c_m, c_n) = self.dim();
    let k = match (a_trans, b_trans) {
      (Transpose::N, Transpose::N) => {
        assert_eq!(c_m, a_m);
        assert_eq!(c_n, b_n);
        assert_eq!(a_n, b_m);
        a_n
      }
      (Transpose::T, Transpose::N) => {
        assert_eq!(c_m, a_n);
        assert_eq!(c_n, b_n);
        assert_eq!(a_m, b_m);
        a_m
      }
      (Transpose::N, Transpose::T) => {
        assert_eq!(c_m, a_m);
        assert_eq!(c_n, b_m);
        assert_eq!(a_n, b_n);
        a_n
      }
      (Transpose::T, Transpose::T) => {
        assert_eq!(c_m, a_n);
        assert_eq!(c_n, b_m);
        assert_eq!(a_m, b_n);
        a_m
      }
    };
    let (a_s0, lda) = a.stride();
    let (b_s0, ldb) = b.stride();
    let (c_s0, ldc) = self.stride();
    assert_eq!(1, a_s0);
    assert_eq!(1, b_s0);
    assert_eq!(1, c_s0);
    unsafe { cblas_sgemm(
        CblasOrder::ColMajor,
        match a_trans {
          Transpose::N => CblasTranspose::NoTrans,
          Transpose::T => CblasTranspose::Trans,
        },
        match b_trans {
          Transpose::N => CblasTranspose::NoTrans,
          Transpose::T => CblasTranspose::Trans,
        },
        c_m as _, c_n as _, k as _,
        alpha,
        a.data_buf.as_ptr(),
        lda as _,
        b.data_buf.as_ptr(),
        ldb as _,
        beta,
        self.data_buf.as_mut_ptr(),
        ldc as _,
    ) };
  }
}

impl<'a> Array2dViewMut<'a, f64> {
  pub fn matrix_prod(&'a mut self) {
    unimplemented!();
  }
}
<|endoftext|>


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

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("/tmp/_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;

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

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate home;
extern crate smol_str;

use smol_str::SmolStr;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Version {
    name: SmolStr,
    vers: SmolStr,
    deps: Vec<Dependency>,
    cksum: Box<str>,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Dependency {
    name: SmolStr,
    req: SmolStr,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<Box<str>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    kind: Option<SmolStr>,
    #[serde(skip_serializing_if = "Option::is_none")]
    package: Option<Box<str>>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        self.target.as_deref()
    }

    pub fn kind(&self) -> Option<&str> {
        self.kind.as_deref()
    }

    pub fn package(&self) -> Option<&str> {
        self.package.as_deref()
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
///
/// Silently ignores crates that can't be loaded/parsed
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(p) = self.0.next() {
            if let Ok(c) = Crate::new_checked(&p) {
                return Some(c)
            }
        }
        None
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

fn fetch_opts<'cb>() -> git2::FetchOptions<'cb> {
    let mut proxy_opts = git2::ProxyOptions::new();
    proxy_opts.auto();
    let mut fetch_opts = git2::FetchOptions::new();
    fetch_opts.proxy_options(proxy_opts);
    fetch_opts
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Use Cargo's own index in `CARGO_HOME` (`~/.cargo/registry/index`)
    pub fn new_cargo_default() -> Index {
        let cargo_home = home::cargo_home().unwrap_or_default();
        Self::new(cargo_home.join("registry").join("index").join("github.com-1ecc6299db9ec823"))
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin").ok()
                    // Cargo creates a checkout without an origin set,
                    // so default to true in case of missing origin
                    .map_or(true, |remote| remote.url().map_or(true, |url| url == INDEX_GIT_URL))
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        git2::build::RepoBuilder::new()
            .fetch_options(fetch_opts())
            .clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")
            .or_else(|_| repo.remote_anonymous(INDEX_GIT_URL))?;
        origin_remote.fetch(&["master"], Some(&mut fetch_opts()), None)?;
        let oid = repo.refname_to_id("FETCH_HEAD")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        let name_lower = crate_name.to_ascii_lowercase();
        if !name_lower.is_ascii() {
            return None;
        }
        let path = match name_lower.len() {
            0 => return None,
            1 => self.path.join("1"),
            2 => self.path.join("2"),
            3 => self.path.join("3").join(&name_lower[0..1]),
            _ => self.path.join(&name_lower[0..2]).join(&name_lower[2..4]),
        }.join(name_lower);
        if path.exists() {
            Crate::new_checked(path.as_path()).ok()
        } else {
            None
        }
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    #[doc(hidden)]
    #[deprecated(note = "this may panic. use new_checked() instead")]
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        Self::new_checked(index_path).unwrap()
    }

    /// Parse the file with crate versions.
    ///
    /// The file must contain at least one version.
    pub fn new_checked<P: AsRef<Path>>(index_path: P) -> io::Result<Crate> {
        let lines = std::fs::read(index_path)?;
        // Trim last newline
        let mut lines = &lines[..];
        while lines.get(lines.len()-1) == Some(&b'\n') {
            lines = &lines[..lines.len()-1];
        }

        #[inline(always)]
        fn is_newline(&c: &u8) -> bool { c == b'\n' }
        let mut versions = Vec::with_capacity(lines.split(is_newline).count());
        for line in lines.split(is_newline) {
            let version: Version = serde_json::from_slice(line).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
            versions.push(version);
        }
        if versions.is_empty() {
            return Err(io::Error::new(io::ErrorKind::Other, "crate must have versions"));
        }
        Ok(Crate { versions })
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    /// Oldest version.
    ///
    /// Warning: may not be the lowest version number.
    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    /// Most recently published version. Warning: may not be the highest version.
    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_cargo_default_updates() {
        let index = Index::new_cargo_default();
        index.update().map_err(|e| format!("could not fetch cargo's index in {}: {}", index.path().display(), e)).unwrap();
        assert!(index.crate_("crates-index").is_some());
        assert!(index.crate_("toml").is_some());
        assert!(index.crate_("gcc").is_some());
        assert!(index.crate_("cc").is_some());
        assert!(index.crate_("CC").is_some());
        assert!(index.crate_("無").is_none());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<commit_msg>Use boxed slices instead of resizeable Vecs<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("/tmp/_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;

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

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate home;
extern crate smol_str;

use smol_str::SmolStr;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Version {
    name: SmolStr,
    vers: SmolStr,
    deps: Box<[Dependency]>,
    cksum: Box<str>,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Dependency {
    name: SmolStr,
    req: SmolStr,
    features: Box<[String]>,
    optional: bool,
    default_features: bool,
    target: Option<Box<str>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    kind: Option<SmolStr>,
    #[serde(skip_serializing_if = "Option::is_none")]
    package: Option<Box<str>>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        self.target.as_deref()
    }

    pub fn kind(&self) -> Option<&str> {
        self.kind.as_deref()
    }

    pub fn package(&self) -> Option<&str> {
        self.package.as_deref()
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
///
/// Silently ignores crates that can't be loaded/parsed
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(p) = self.0.next() {
            if let Ok(c) = Crate::new_checked(&p) {
                return Some(c)
            }
        }
        None
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

fn fetch_opts<'cb>() -> git2::FetchOptions<'cb> {
    let mut proxy_opts = git2::ProxyOptions::new();
    proxy_opts.auto();
    let mut fetch_opts = git2::FetchOptions::new();
    fetch_opts.proxy_options(proxy_opts);
    fetch_opts
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Use Cargo's own index in `CARGO_HOME` (`~/.cargo/registry/index`)
    pub fn new_cargo_default() -> Index {
        let cargo_home = home::cargo_home().unwrap_or_default();
        Self::new(cargo_home.join("registry").join("index").join("github.com-1ecc6299db9ec823"))
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin").ok()
                    // Cargo creates a checkout without an origin set,
                    // so default to true in case of missing origin
                    .map_or(true, |remote| remote.url().map_or(true, |url| url == INDEX_GIT_URL))
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        git2::build::RepoBuilder::new()
            .fetch_options(fetch_opts())
            .clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")
            .or_else(|_| repo.remote_anonymous(INDEX_GIT_URL))?;
        origin_remote.fetch(&["master"], Some(&mut fetch_opts()), None)?;
        let oid = repo.refname_to_id("FETCH_HEAD")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        let name_lower = crate_name.to_ascii_lowercase();
        if !name_lower.is_ascii() {
            return None;
        }
        let path = match name_lower.len() {
            0 => return None,
            1 => self.path.join("1"),
            2 => self.path.join("2"),
            3 => self.path.join("3").join(&name_lower[0..1]),
            _ => self.path.join(&name_lower[0..2]).join(&name_lower[2..4]),
        }.join(name_lower);
        if path.exists() {
            Crate::new_checked(path.as_path()).ok()
        } else {
            None
        }
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Crate {
    versions: Box<[Version]>,
}

impl Crate {
    #[doc(hidden)]
    #[deprecated(note = "this may panic. use new_checked() instead")]
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        Self::new_checked(index_path).unwrap()
    }

    /// Parse the file with crate versions.
    ///
    /// The file must contain at least one version.
    pub fn new_checked<P: AsRef<Path>>(index_path: P) -> io::Result<Crate> {
        let lines = std::fs::read(index_path)?;
        // Trim last newline
        let mut lines = &lines[..];
        while lines.get(lines.len()-1) == Some(&b'\n') {
            lines = &lines[..lines.len()-1];
        }

        #[inline(always)]
        fn is_newline(&c: &u8) -> bool { c == b'\n' }
        let mut versions = Vec::with_capacity(lines.split(is_newline).count());
        for line in lines.split(is_newline) {
            let version: Version = serde_json::from_slice(line).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
            versions.push(version);
        }
        if versions.is_empty() {
            return Err(io::Error::new(io::ErrorKind::Other, "crate must have versions"));
        }
        debug_assert_eq!(versions.len(), versions.capacity());
        Ok(Crate {
            versions: versions.into_boxed_slice(),
        })
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    /// Oldest version.
    ///
    /// Warning: may not be the lowest version number.
    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    /// Most recently published version. Warning: may not be the highest version.
    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_cargo_default_updates() {
        let index = Index::new_cargo_default();
        index.update().map_err(|e| format!("could not fetch cargo's index in {}: {}", index.path().display(), e)).unwrap();
        assert!(index.crate_("crates-index").is_some());
        assert!(index.crate_("toml").is_some());
        assert!(index.crate_("gcc").is_some());
        assert!(index.crate_("cc").is_some());
        assert!(index.crate_("CC").is_some());
        assert!(index.crate_("無").is_none());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<|endoftext|>


<commit_before>//! Multiboot v1 library
//!
//! # Additional documentation
//!   * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
//!   * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
//!

#![no_std]
#![crate_name = "multiboot"]
#![crate_type = "lib"]

macro_rules! round_up {
    ($num:expr, $s:expr) => {
        (($num + $s - 1) / $s) * $s
    };
}

macro_rules! flag {
    ($doc:meta, $fun:ident, $bit:expr) => (
        #[$doc]
        fn $fun(&self) -> bool {
            //assert!($bit <= 31);
            (self.header.flags & (1 << $bit)) > 0
        }

        paste::paste! {
            #[$doc]
            fn [< set_ $fun >] (&mut self, flag: bool) {
                //assert!($bit <= 31);
                self.header.flags = if flag {
                    self.header.flags | (1 << $bit)
                } else {
                    self.header.flags & !(1 << $bit)
                };
            }
        }
    );

    // syms field is valid if bit 4 or 5 is set, wtf?
    ($doc:meta, $fun:ident, $bit1:expr, $bit2:expr) => (
        #[$doc]
        fn $fun(&self) -> bool {
            //assert!($bit1 <= 31);
            //assert!($bit2 <= 31);
            (self.header.flags & (1 << $bit1)) > 0 || (self.header.flags & (1 << $bit2)) > 0
        }
    );
}

mod information;
pub use information::SIGNATURE_EAX;
pub use information::PAddr;
pub use information::Multiboot;
pub use information::MultibootInfo;
pub use information::BootDevice;
pub use information::MemoryType;
pub use information::MemoryEntry;
pub use information::MemoryMapIter;
pub use information::Module;
pub use information::ModuleIter;
pub use information::FramebufferTable;
pub use information::ColorInfoType;
pub use information::ColorInfoRgb;

mod header;
pub use header::Header;
pub use header::MultibootAddresses;
pub use header::MultibootVideoMode;
pub use header::VideoModeType;
<commit_msg>Publish flag getters<commit_after>//! Multiboot v1 library
//!
//! # Additional documentation
//!   * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
//!   * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
//!

#![no_std]
#![crate_name = "multiboot"]
#![crate_type = "lib"]

macro_rules! round_up {
    ($num:expr, $s:expr) => {
        (($num + $s - 1) / $s) * $s
    };
}

macro_rules! flag {
    ($doc:meta, $fun:ident, $bit:expr) => (
        #[$doc]
        pub fn $fun(&self) -> bool {
            //assert!($bit <= 31);
            (self.header.flags & (1 << $bit)) > 0
        }

        paste::paste! {
            #[$doc]
            fn [< set_ $fun >] (&mut self, flag: bool) {
                //assert!($bit <= 31);
                self.header.flags = if flag {
                    self.header.flags | (1 << $bit)
                } else {
                    self.header.flags & !(1 << $bit)
                };
            }
        }
    );

    // syms field is valid if bit 4 or 5 is set, wtf?
    ($doc:meta, $fun:ident, $bit1:expr, $bit2:expr) => (
        #[$doc]
        fn $fun(&self) -> bool {
            //assert!($bit1 <= 31);
            //assert!($bit2 <= 31);
            (self.header.flags & (1 << $bit1)) > 0 || (self.header.flags & (1 << $bit2)) > 0
        }
    );
}

mod information;
pub use information::SIGNATURE_EAX;
pub use information::PAddr;
pub use information::Multiboot;
pub use information::MultibootInfo;
pub use information::BootDevice;
pub use information::MemoryType;
pub use information::MemoryEntry;
pub use information::MemoryMapIter;
pub use information::Module;
pub use information::ModuleIter;
pub use information::FramebufferTable;
pub use information::ColorInfoType;
pub use information::ColorInfoRgb;

mod header;
pub use header::Header;
pub use header::MultibootAddresses;
pub use header::MultibootVideoMode;
pub use header::VideoModeType;
<|endoftext|>