<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Discover or identify devices that may belong to Stratis.

use std::{
    collections::HashMap,
    fs::OpenOptions,
    path::{Path, PathBuf},
};

use libudev;

use devicemapper::Device;

use crate::engine::{
    strat_engine::backstore::{
        metadata::{device_identifiers, StratisIdentifiers},
        udev::{block_enumerator, decide_ownership, UdevOwnership},
    },
    types::PoolUuid,
};

// A wrapper for obtaining the device number as a devicemapper Device
// which interprets absence of the value as an error, which it is in this
// context.
fn device_to_devno_wrapper(device: &libudev::Device) -> Result<Device, String> {
    device
        .devnum()
        .ok_or_else(|| "udev entry did not contain a device number".into())
        .map(Device::from)
}

// A wrapper around the metadata module's device_identifers method
// which also handles failure to open a device for reading.
// Returns an error if the device could not be opened for reading.
// Returns Ok(Err(...)) if there was an error while reading the
// Stratis identifiers from the device.
// Returns Ok(Ok(None)) if the identifers did not appear to be on
// the device.
fn device_identifiers_wrapper(
    devnode: &Path,
) -> Result<Result<Option<StratisIdentifiers>, String>, String> {
    OpenOptions::new()
        .read(true)
        .open(devnode)
        .as_mut()
        .map_err(|err| {
            format!(
                "device {} could not be opened for reading: {}",
                devnode.display(),
                err
            )
        })
        .map(|f| {
            device_identifiers(f).map_err(|err| {
                format!(
                    "encountered an error while reading Stratis header for device {}: {}",
                    devnode.display(),
                    err
                )
            })
        })
}

/// Process a device which udev information indicates is a Stratis device.
fn process_stratis_device(dev: &libudev::Device) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    match dev.devnode() {
        Some(devnode) => {
            match (
                device_to_devno_wrapper(dev),
                device_identifiers_wrapper(devnode),
            ) {
                (Err(err), _) | (_, Err(err)) | (_, Ok(Err(err))) => {
                    warn!("udev identified device {} as a Stratis device but {}, disregarding the device",
                          devnode.display(),
                          err);
                    None
                }
                (_, Ok(Ok(None))) => {
                    warn!("udev identified device {} as a Stratis device but there appeared to be no Stratis metadata on the device, disregarding the device",
                          devnode.display());
                    None
                }
                (Ok(devno), Ok(Ok(Some(identifiers)))) => {
                    Some((identifiers, devno, devnode.to_path_buf()))
                }
            }
        }
        None => {
            warn!("udev identified a device as a Stratis device, but the udev entry for the device had no device node, disregarding device");
            None
        }
    }
}

/// Process a device which udev information indicates is unowned.
fn process_unowned_device(dev: &libudev::Device) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    match dev.devnode() {
        Some(devnode) => {
            match (
                device_to_devno_wrapper(dev),
                device_identifiers_wrapper(devnode),
            ) {
                (Err(err), _) | (_, Err(err)) => {
                    warn!("udev identified device {} as a block device but {}, disregarding the device",
                          devnode.display(),
                          err);
                    None
                }
                // FIXME: Refine error return in StaticHeader::setup(),
                // so it can be used to distinguish between signficant
                // and insignficant errors and then use that ability to
                // distinguish here between different levels of
                // severity.
                (_, Ok(Err(err))) => {
                    debug!("udev identified device {} as a block device but {}, disregarding the device",
                           devnode.display(),
                           err);
                    None
                }
                (_, Ok(Ok(None))) => None,
                (Ok(devno), Ok(Ok(Some(identifiers)))) => {
                    Some((identifiers, devno, devnode.to_path_buf()))
                }
            }
        }
        None => {
            warn!("udev identified a device as a block device, but the udev entry for the device had no device node, disregarding the device");
            None
        }
    }
}

// Use udev to identify all block devices and return the subset of those
// that have Stratis signatures.
pub fn find_all_block_devices_with_stratis_signatures(
) -> libudev::Result<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;

    let pool_map = enumerator
        .scan_devices()?
        .filter_map(|dev| identify_block_device(&dev))
        .fold(HashMap::new(), |mut acc, (identifiers, device, devnode)| {
            acc.entry(identifiers.pool_uuid)
                .or_insert_with(HashMap::new)
                .insert(device, devnode);
            acc
        });

    Ok(pool_map)
}

// Find all devices identified by udev as Stratis devices.
fn find_all_stratis_devices() -> libudev::Result<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;
    enumerator.match_property("ID_FS_TYPE", "stratis")?;

    let pool_map = enumerator
        .scan_devices()?
        .filter_map(|dev| identify_stratis_device(&dev))
        .fold(HashMap::new(), |mut acc, (identifiers, device, devnode)| {
            acc.entry(identifiers.pool_uuid)
                .or_insert_with(HashMap::new)
                .insert(device, devnode);
            acc
        });
    Ok(pool_map)
}

// Identify a device that udev enumeration has already picked up as a Stratis
// device. Return None if the device does not, after all, appear to be a Stratis
// device. Log anything unusual at an appropriate level.
fn identify_stratis_device(dev: &libudev::Device) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    let initialized = dev.is_initialized();
    if !initialized {
        warn!("Found a udev entry for a device identified as a Stratis device, but udev also identified it as uninitialized, disregarding the device");
        return None;
    };

    match decide_ownership(dev) {
        Err(err) => {
            warn!("Could not determine ownership of a block device identified as a Stratis device by udev, disregarding the device: {}",
                  err);
            None
        }
        Ok(ownership) => match ownership {
            UdevOwnership::Stratis => process_stratis_device(dev),
            UdevOwnership::MultipathMember => None,
            _ => {
                warn!("udev enumeration identified this device as a Stratis block device but on further examination it appears not to belong to Stratis");
                None
            }
        },
    }
}

/// Identify a block device in the context where a udev event has been
/// captured for some block device. Return None if the device does not
/// appear to be a Stratis device. Log at an appropriate level on all errors.
pub fn identify_block_device(
    dev: &libudev::Device,
) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    let initialized = dev.is_initialized();
    if !initialized {
        debug!("Found a udev entry for a device identified as a block device, but udev also identified it as uninitialized, disregarding the device");
        return None;
    };

    match decide_ownership(dev) {
        Err(err) => {
            warn!(
                "Could not determine ownership of a udev block device, disregarding the device: {}",
                err
            );
            None
        }
        Ok(ownership) => match ownership {
            UdevOwnership::Stratis => process_stratis_device(dev),
            UdevOwnership::Unowned => process_unowned_device(dev),
            _ => None,
        },
    }
}

/// Retrieve all block devices that should be made use of by the
/// Stratis engine. This excludes Stratis block devices that appear to be
/// multipath members.
///
/// Includes a fallback path, which is used if no Stratis block devices are
/// found using the obvious udev property- and enumerator-based approach.
/// This fallback path is more expensive, because it must search all block
/// devices via udev rather than just all Stratis block devices.
///
/// Omits any device that appears problematic in some way.
///
/// Return an error only on a failure to construct or scan with a udev
/// enumerator.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> libudev::Result<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    info!("Beginning initial search for Stratis block devices");
    let pool_map = find_all_stratis_devices()?;

    if pool_map.is_empty() {
        // No Stratis devices have been found, possible reasons are:
        // 1. There are none
        // 2. There are some but libblkid version is less than 2.32, so
        // Stratis devices are not recognized by udev.
        // 3. There are many incomplete udev entries, because this code is
        // being run before the udev database is populated.
        //
        // Try again to find Stratis block devices, but this time enumerate
        // all block devices, not just all the ones that can be identified
        // as Stratis blockdevs by udev, and process only those that appear
        // unclaimed or appear to be claimed by Stratis (and not
        // multipath members).

        info!("Could not identify any Stratis devices by a udev search for devices with ID_FS_TYPE=\"stratis\"; using fallback search mechanism");

        find_all_block_devices_with_stratis_signatures()
    } else {
        Ok(pool_map)
    }
}
<commit_msg>Remove comment about libblkid version in find_all method<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Discover or identify devices that may belong to Stratis.

use std::{
    collections::HashMap,
    fs::OpenOptions,
    path::{Path, PathBuf},
};

use libudev;

use devicemapper::Device;

use crate::engine::{
    strat_engine::backstore::{
        metadata::{device_identifiers, StratisIdentifiers},
        udev::{block_enumerator, decide_ownership, UdevOwnership},
    },
    types::PoolUuid,
};

// A wrapper for obtaining the device number as a devicemapper Device
// which interprets absence of the value as an error, which it is in this
// context.
fn device_to_devno_wrapper(device: &libudev::Device) -> Result<Device, String> {
    device
        .devnum()
        .ok_or_else(|| "udev entry did not contain a device number".into())
        .map(Device::from)
}

// A wrapper around the metadata module's device_identifers method
// which also handles failure to open a device for reading.
// Returns an error if the device could not be opened for reading.
// Returns Ok(Err(...)) if there was an error while reading the
// Stratis identifiers from the device.
// Returns Ok(Ok(None)) if the identifers did not appear to be on
// the device.
fn device_identifiers_wrapper(
    devnode: &Path,
) -> Result<Result<Option<StratisIdentifiers>, String>, String> {
    OpenOptions::new()
        .read(true)
        .open(devnode)
        .as_mut()
        .map_err(|err| {
            format!(
                "device {} could not be opened for reading: {}",
                devnode.display(),
                err
            )
        })
        .map(|f| {
            device_identifiers(f).map_err(|err| {
                format!(
                    "encountered an error while reading Stratis header for device {}: {}",
                    devnode.display(),
                    err
                )
            })
        })
}

/// Process a device which udev information indicates is a Stratis device.
fn process_stratis_device(dev: &libudev::Device) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    match dev.devnode() {
        Some(devnode) => {
            match (
                device_to_devno_wrapper(dev),
                device_identifiers_wrapper(devnode),
            ) {
                (Err(err), _) | (_, Err(err)) | (_, Ok(Err(err))) => {
                    warn!("udev identified device {} as a Stratis device but {}, disregarding the device",
                          devnode.display(),
                          err);
                    None
                }
                (_, Ok(Ok(None))) => {
                    warn!("udev identified device {} as a Stratis device but there appeared to be no Stratis metadata on the device, disregarding the device",
                          devnode.display());
                    None
                }
                (Ok(devno), Ok(Ok(Some(identifiers)))) => {
                    Some((identifiers, devno, devnode.to_path_buf()))
                }
            }
        }
        None => {
            warn!("udev identified a device as a Stratis device, but the udev entry for the device had no device node, disregarding device");
            None
        }
    }
}

/// Process a device which udev information indicates is unowned.
fn process_unowned_device(dev: &libudev::Device) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    match dev.devnode() {
        Some(devnode) => {
            match (
                device_to_devno_wrapper(dev),
                device_identifiers_wrapper(devnode),
            ) {
                (Err(err), _) | (_, Err(err)) => {
                    warn!("udev identified device {} as a block device but {}, disregarding the device",
                          devnode.display(),
                          err);
                    None
                }
                // FIXME: Refine error return in StaticHeader::setup(),
                // so it can be used to distinguish between signficant
                // and insignficant errors and then use that ability to
                // distinguish here between different levels of
                // severity.
                (_, Ok(Err(err))) => {
                    debug!("udev identified device {} as a block device but {}, disregarding the device",
                           devnode.display(),
                           err);
                    None
                }
                (_, Ok(Ok(None))) => None,
                (Ok(devno), Ok(Ok(Some(identifiers)))) => {
                    Some((identifiers, devno, devnode.to_path_buf()))
                }
            }
        }
        None => {
            warn!("udev identified a device as a block device, but the udev entry for the device had no device node, disregarding the device");
            None
        }
    }
}

// Use udev to identify all block devices and return the subset of those
// that have Stratis signatures.
pub fn find_all_block_devices_with_stratis_signatures(
) -> libudev::Result<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;

    let pool_map = enumerator
        .scan_devices()?
        .filter_map(|dev| identify_block_device(&dev))
        .fold(HashMap::new(), |mut acc, (identifiers, device, devnode)| {
            acc.entry(identifiers.pool_uuid)
                .or_insert_with(HashMap::new)
                .insert(device, devnode);
            acc
        });

    Ok(pool_map)
}

// Find all devices identified by udev as Stratis devices.
fn find_all_stratis_devices() -> libudev::Result<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;
    enumerator.match_property("ID_FS_TYPE", "stratis")?;

    let pool_map = enumerator
        .scan_devices()?
        .filter_map(|dev| identify_stratis_device(&dev))
        .fold(HashMap::new(), |mut acc, (identifiers, device, devnode)| {
            acc.entry(identifiers.pool_uuid)
                .or_insert_with(HashMap::new)
                .insert(device, devnode);
            acc
        });
    Ok(pool_map)
}

// Identify a device that udev enumeration has already picked up as a Stratis
// device. Return None if the device does not, after all, appear to be a Stratis
// device. Log anything unusual at an appropriate level.
fn identify_stratis_device(dev: &libudev::Device) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    let initialized = dev.is_initialized();
    if !initialized {
        warn!("Found a udev entry for a device identified as a Stratis device, but udev also identified it as uninitialized, disregarding the device");
        return None;
    };

    match decide_ownership(dev) {
        Err(err) => {
            warn!("Could not determine ownership of a block device identified as a Stratis device by udev, disregarding the device: {}",
                  err);
            None
        }
        Ok(ownership) => match ownership {
            UdevOwnership::Stratis => process_stratis_device(dev),
            UdevOwnership::MultipathMember => None,
            _ => {
                warn!("udev enumeration identified this device as a Stratis block device but on further examination it appears not to belong to Stratis");
                None
            }
        },
    }
}

/// Identify a block device in the context where a udev event has been
/// captured for some block device. Return None if the device does not
/// appear to be a Stratis device. Log at an appropriate level on all errors.
pub fn identify_block_device(
    dev: &libudev::Device,
) -> Option<(StratisIdentifiers, Device, PathBuf)> {
    let initialized = dev.is_initialized();
    if !initialized {
        debug!("Found a udev entry for a device identified as a block device, but udev also identified it as uninitialized, disregarding the device");
        return None;
    };

    match decide_ownership(dev) {
        Err(err) => {
            warn!(
                "Could not determine ownership of a udev block device, disregarding the device: {}",
                err
            );
            None
        }
        Ok(ownership) => match ownership {
            UdevOwnership::Stratis => process_stratis_device(dev),
            UdevOwnership::Unowned => process_unowned_device(dev),
            _ => None,
        },
    }
}

/// Retrieve all block devices that should be made use of by the
/// Stratis engine. This excludes Stratis block devices that appear to be
/// multipath members.
///
/// Includes a fallback path, which is used if no Stratis block devices are
/// found using the obvious udev property- and enumerator-based approach.
/// This fallback path is more expensive, because it must search all block
/// devices via udev rather than just all Stratis block devices.
///
/// Omits any device that appears problematic in some way.
///
/// Return an error only on a failure to construct or scan with a udev
/// enumerator.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> libudev::Result<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    info!("Beginning initial search for Stratis block devices");
    let pool_map = find_all_stratis_devices()?;

    if pool_map.is_empty() {
        // No Stratis devices have been found, possible reasons are:
        // 1. There are none
        // 2. There are many incomplete udev entries, because this code is
        // being run before the udev database is populated.
        //
        // Try again to find Stratis block devices, but this time enumerate
        // all block devices, not just all the ones that can be identified
        // as Stratis blockdevs by udev, and process only those that appear
        // unclaimed or appear to be claimed by Stratis (and not
        // multipath members).

        info!("Could not identify any Stratis devices by a udev search for devices with ID_FS_TYPE=\"stratis\"; using fallback search mechanism");

        find_all_block_devices_with_stratis_signatures()
    } else {
        Ok(pool_map)
    }
}
<|endoftext|>


<commit_before>//! It's a tree!

use std::ptr;

use rustwlc::WlcView;

use super::container::*;

#[derive(Debug, PartialEq, Eq)]
pub struct Node {
    // We need a mut pointer so we can modify the parent
    parent: *mut Node,
    val: Container,
    children: Vec<Node>
}

impl Node {
    /// Create a new node with the existing value.
    /// For root-style constructors.
    pub fn new(val: Container) -> Node {
        Node {
            parent: ptr::null_mut(),
            val: val,
            children: Vec::new()
        }
    }

    /// Add a new child node to this node, using a value
    pub fn new_child(&mut self, val: Container) -> Result<&mut Node, String> {
        if ! self.val.get_type().can_have_child(val.get_type()) {
            return Err(format!("{:?}({:?}) cannot be a child of {:?}({:?})",
                               val, val.get_type(),
                               self.val, self.val.get_type()));
        }
        let self_mut = self as *mut Node;
        self.children.push(Node {
            parent: self_mut,
            val: val,
            children: Vec::new()
        });
        let last_ix = self.children.len() -1;
        Ok(&mut self.children[last_ix])
    }

    /// Whether this node has a (currently-reachable) parent
    #[allow(dead_code)]
    pub fn has_parent(&self) -> bool {
        !self.parent.is_null()
    }

    /// Gets the type of container this node holds
    pub fn get_container_type(&self) -> ContainerType {
        self.val.get_type()
    }

    /// Tries to get an ancestor of the requested type
    pub fn get_ancestor_of_type(&self, container_type: ContainerType)
                                -> Option<&Node> {
        let mut maybe_parent = self.get_parent();
        loop {
            if let Some(parent) = maybe_parent {
                if parent.get_container_type() == container_type {
                    return Some(parent);
                }
                maybe_parent = parent.get_parent();
            }
            else {
                return None;
            }
        }
    }

    /// Gets a node by handle
    pub fn find_view_by_handle(&self, view_handle: &WlcView) -> Option<&Node>{
        match self.get_val() {
            &Container::View { ref handle, .. } => {
                if view_handle == handle {
                    Some(self)
                } else {
                    None
                }
            },
            _ => {
                for child in self.get_children() {
                    if let Some(view) = child.find_view_by_handle(view_handle) {
                        return Some(view);
                    }
                }
                return None;
            }
        }
    }

    /// Gets the parent of this node (if it exists)
    pub fn get_parent(&self) -> Option<&mut Node> {
        if self.parent.is_null() {
            return None;
        }
        unsafe {
            return Some(&mut *self.parent);
        }
    }

    /// Borrow the children of this node.
    pub fn get_children(&self) -> &[Node] {
        &self.children
    }

    /// Mutably borrow the children of this mutable node
    pub fn get_children_mut(&mut self) -> &mut[Node] {
        &mut self.children
    }

    /// Remove a child at the given index
    #[allow(dead_code)]
    pub fn remove_child_at(&mut self, index: usize) -> Option<Node> {
        if index > self.children.len() - 1 {
            return None;
        }
        let mut child = self.children.remove(index);
        child.parent = ptr::null_mut();
        return Some(child);
    }

    /// Moves another node to be a sibling of this node.
    #[allow(dead_code)]
    pub fn add_sibling(&self, node: Node) -> Result<(), ()> {
        if let Some(parent) = self.get_parent() {
            node.move_to(parent);
            Ok(())
        }
        else {
            Err(())
        }
    }

    /// Whether this node is a parent of another node
    #[allow(dead_code)]
    pub fn is_parent_of(&self, other: &Node) -> bool {
        // Fun fact, other.parent == self as *const Node won't compile
        self as *const Node == other.parent
    }

    /// Remove a node from its parent.
    /// This method will mutate the parent if it exists.
    pub fn remove_from_parent(&mut self) -> Option<Node> {
        let mut result: Option<Node> = None;
        if let Some(mut parent) = self.get_parent() {
            if let Some(index) = parent.children.iter().position(|c| c == self) {
                result = Some(parent.children.remove(index));
            }
        }
        self.parent = ptr::null_mut();
        result
    }

    /// Removes a child from self
    pub fn remove_child(&mut self, other: &Node) -> Option<Node> {
        if let Some(index) = self.children.iter().position(|c| c == other) {
            let mut child = self.children.remove(index);
            child.parent = ptr::null_mut();
            Some(child)
        }
        else {
            None
        }
    }

    /// Removes this node from its current parent and adds it to the given node
    /// as a child
    pub fn move_to(mut self, new_parent: &mut Node) {
        self.remove_from_parent();
        self.parent = new_parent as *mut Node;
        new_parent.children.push(self);
    }

    /// Gets the container that this node has
    pub fn get_val(&self) -> &Container {
        &self.val
    }

    /// Sets the visibility of the container and its children
    pub fn set_visibility(&mut self, visibility: bool) {
        self.val.set_visibility(visibility);
        for child in self.get_children_mut() {
            child.set_visibility(visibility);
        }
    }

    /// Attempts to get the Node as a mutable reference by going through it's
    /// child to get a mutable reference to it.
    pub fn as_mut<'a>(&'a self) -> &'a mut Node {
        let maybe_parent = self.get_parent();
        if maybe_parent.is_some() {
            let parent: &'a mut Node = self.get_parent().unwrap();
                for child in parent.get_children_mut() {
                    if *child == *self {
                        return child;
                    }
                };
        }
        // Error, give reason why
        if self.get_val().get_type() == ContainerType::Root {
            panic!("Tried to take as_mut of root")
        } else {
            panic!("Tried to take as_mut of a node not in the tree")
        }
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        let children: &mut Vec<Node> = &mut self.children;
        for mut child in children {
            child.parent = ptr::null_mut();
        }
    }
}

unsafe impl Sync for Node {}
unsafe impl Send for Node {}

#[cfg(test)]
mod tests {
    use rustwlc::*;
    const FAKE_GEOMETRY: Geometry = Geometry {
        size: Size { w: 0, h:0 },
        origin: Point { x: 0, y: 0}
    };
    use super::Node;
    use super::super::container::*;

    /// Nodes can have children added to them
    #[test]
    fn new_child() {
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap(); // This is okay
        {
            let mut third_child = root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            third_child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            //root.new_child(Root); // Have to wait for 3rd child to drop
        }
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap(); // Now this works
        assert_eq!(root.children.len(), 4);
    }

    #[test]
    fn has_get_parent() {
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        assert!(!root.has_parent(), "Root has a parent");
        assert_eq!(root.get_parent(), None);

        let child = root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        assert!(child.has_parent(), "Child does not have parent");
        assert!(child.get_parent().is_some(), "Child does not have parent");
        let parent = child.get_parent().expect("Asserted child has parent");
        assert_eq!(parent.get_container_type(), ContainerType::Container);
    }

    #[test]
    fn get_container_type() {
        use rustwlc::*;
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        assert_eq!(root.get_container_type(), ContainerType::Container);
        {
            let wksp = root.new_child(
                Container::new_view(WlcView::root())).unwrap();
            assert_eq!(wksp.get_container_type(), ContainerType::View);
        }
        {
            let container = root.new_child(Container::Container {
                layout: Layout::Horizontal, visible: false,
                floating: false, focused: false, geometry: Geometry {
                    size: Size { w: 0, h: 0},
                    origin: Point {x: 0, y: 0}
                }
            }).unwrap();
            assert_eq!(container.get_container_type(), ContainerType::Container);
        }
    }

    #[test]
    fn get_children() {
        // Create a root with 3 children. The 3rd child has 2 children.
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        {
            let third_child = root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            third_child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            third_child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        }
        let root_children = root.get_children();
        assert!(!root_children.is_empty(), "Root has children");
        assert_eq!(root_children.len(), 3);
        assert!(root_children.last().is_some(), "Root has final child");
        let third_child = root_children.last().expect("Asserted unwrap!");
        assert_eq!(third_child.get_children().len(), 2);
        let third_child_second_child = third_child.get_children().last()
            .expect("Asserted unwrap!");
        assert!(third_child_second_child.get_children().is_empty(),
                "Grandchild doesn't have children");
    }

    #[test]
    fn get_children_mut() {
        // Start out with one child, use get_mut_children to add grandchild.
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();

        assert!(root.get_children().last().expect("Root has child")
                .get_children().is_empty(), "Root has no grandchildren");

        {
            let mut children = root.get_children_mut();
            assert_eq!(children.len(), 1);

            let mut child = &mut children[0];
            child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        }

        assert_eq!(root.get_children().last().expect("Asserted unwrap!")
                .get_children().len(), 1);
    }

    #[test]
    fn remove_child_at() {
        use rustwlc::handle::*;
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        root.new_child(Container::new_view(WlcView::root())).unwrap();
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();

        let worksp = root.remove_child_at(1).expect("Index should be valid");
        assert_eq!(worksp.get_container_type(), ContainerType::View);
        assert_eq!(root.get_children().len(), 2)
    }
}
<commit_msg>Dropping a View node now closes the WlcView<commit_after>//! It's a tree!

use std::ptr;

use rustwlc::WlcView;

use super::container::*;

#[derive(Debug, PartialEq, Eq)]
pub struct Node {
    // We need a mut pointer so we can modify the parent
    parent: *mut Node,
    val: Container,
    children: Vec<Node>
}

impl Node {
    /// Create a new node with the existing value.
    /// For root-style constructors.
    pub fn new(val: Container) -> Node {
        Node {
            parent: ptr::null_mut(),
            val: val,
            children: Vec::new()
        }
    }

    /// Add a new child node to this node, using a value
    pub fn new_child(&mut self, val: Container) -> Result<&mut Node, String> {
        if ! self.val.get_type().can_have_child(val.get_type()) {
            return Err(format!("{:?}({:?}) cannot be a child of {:?}({:?})",
                               val, val.get_type(),
                               self.val, self.val.get_type()));
        }
        let self_mut = self as *mut Node;
        self.children.push(Node {
            parent: self_mut,
            val: val,
            children: Vec::new()
        });
        let last_ix = self.children.len() -1;
        Ok(&mut self.children[last_ix])
    }

    /// Whether this node has a (currently-reachable) parent
    #[allow(dead_code)]
    pub fn has_parent(&self) -> bool {
        !self.parent.is_null()
    }

    /// Gets the type of container this node holds
    pub fn get_container_type(&self) -> ContainerType {
        self.val.get_type()
    }

    /// Tries to get an ancestor of the requested type
    pub fn get_ancestor_of_type(&self, container_type: ContainerType)
                                -> Option<&Node> {
        let mut maybe_parent = self.get_parent();
        loop {
            if let Some(parent) = maybe_parent {
                if parent.get_container_type() == container_type {
                    return Some(parent);
                }
                maybe_parent = parent.get_parent();
            }
            else {
                return None;
            }
        }
    }

    /// Gets a node by handle
    pub fn find_view_by_handle(&self, view_handle: &WlcView) -> Option<&Node>{
        match self.get_val() {
            &Container::View { ref handle, .. } => {
                if view_handle == handle {
                    Some(self)
                } else {
                    None
                }
            },
            _ => {
                for child in self.get_children() {
                    if let Some(view) = child.find_view_by_handle(view_handle) {
                        return Some(view);
                    }
                }
                return None;
            }
        }
    }

    /// Gets the parent of this node (if it exists)
    pub fn get_parent(&self) -> Option<&mut Node> {
        if self.parent.is_null() {
            return None;
        }
        unsafe {
            return Some(&mut *self.parent);
        }
    }

    /// Borrow the children of this node.
    pub fn get_children(&self) -> &[Node] {
        &self.children
    }

    /// Mutably borrow the children of this mutable node
    pub fn get_children_mut(&mut self) -> &mut[Node] {
        &mut self.children
    }

    /// Remove a child at the given index
    #[allow(dead_code)]
    pub fn remove_child_at(&mut self, index: usize) -> Option<Node> {
        if index > self.children.len() - 1 {
            return None;
        }
        let mut child = self.children.remove(index);
        child.parent = ptr::null_mut();
        return Some(child);
    }

    /// Moves another node to be a sibling of this node.
    #[allow(dead_code)]
    pub fn add_sibling(&self, node: Node) -> Result<(), ()> {
        if let Some(parent) = self.get_parent() {
            node.move_to(parent);
            Ok(())
        }
        else {
            Err(())
        }
    }

    /// Whether this node is a parent of another node
    #[allow(dead_code)]
    pub fn is_parent_of(&self, other: &Node) -> bool {
        // Fun fact, other.parent == self as *const Node won't compile
        self as *const Node == other.parent
    }

    /// Remove a node from its parent.
    /// This method will mutate the parent if it exists.
    pub fn remove_from_parent(&mut self) -> Option<Node> {
        let mut result: Option<Node> = None;
        if let Some(mut parent) = self.get_parent() {
            if let Some(index) = parent.children.iter().position(|c| c == self) {
                result = Some(parent.children.remove(index));
            }
        }
        self.parent = ptr::null_mut();
        result
    }

    /// Removes a child from self
    pub fn remove_child(&mut self, other: &Node) -> Option<Node> {
        if let Some(index) = self.children.iter().position(|c| c == other) {
            let mut child = self.children.remove(index);
            child.parent = ptr::null_mut();
            Some(child)
        }
        else {
            None
        }
    }

    /// Removes this node from its current parent and adds it to the given node
    /// as a child
    pub fn move_to(mut self, new_parent: &mut Node) {
        self.remove_from_parent();
        self.parent = new_parent as *mut Node;
        new_parent.children.push(self);
    }

    /// Gets the container that this node has
    pub fn get_val(&self) -> &Container {
        &self.val
    }

    /// Sets the visibility of the container and its children
    pub fn set_visibility(&mut self, visibility: bool) {
        self.val.set_visibility(visibility);
        for child in self.get_children_mut() {
            child.set_visibility(visibility);
        }
    }

    /// Attempts to get the Node as a mutable reference by going through it's
    /// child to get a mutable reference to it.
    pub fn as_mut<'a>(&'a self) -> &'a mut Node {
        let maybe_parent = self.get_parent();
        if maybe_parent.is_some() {
            let parent: &'a mut Node = self.get_parent().unwrap();
                for child in parent.get_children_mut() {
                    if *child == *self {
                        return child;
                    }
                };
        }
        // Error, give reason why
        if self.get_val().get_type() == ContainerType::Root {
            panic!("Tried to take as_mut of root")
        } else {
            panic!("Tried to take as_mut of a node not in the tree")
        }
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        // We own the view, so we close it if we lose the Node
        if self.get_container_type() == ContainerType::View {
            if let Some(handle) = self.get_val().get_handle() {
                match handle {
                    Handle::View(view) => view.close(),
                    _ => {},
                }
            }
        }
    }
}

unsafe impl Sync for Node {}
unsafe impl Send for Node {}

#[cfg(test)]
mod tests {
    use rustwlc::*;
    const FAKE_GEOMETRY: Geometry = Geometry {
        size: Size { w: 0, h:0 },
        origin: Point { x: 0, y: 0}
    };
    use super::Node;
    use super::super::container::*;

    /// Nodes can have children added to them
    #[test]
    fn new_child() {
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap(); // This is okay
        {
            let mut third_child = root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            third_child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            //root.new_child(Root); // Have to wait for 3rd child to drop
        }
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap(); // Now this works
        assert_eq!(root.children.len(), 4);
    }

    #[test]
    fn has_get_parent() {
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        assert!(!root.has_parent(), "Root has a parent");
        assert_eq!(root.get_parent(), None);

        let child = root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        assert!(child.has_parent(), "Child does not have parent");
        assert!(child.get_parent().is_some(), "Child does not have parent");
        let parent = child.get_parent().expect("Asserted child has parent");
        assert_eq!(parent.get_container_type(), ContainerType::Container);
    }

    #[test]
    fn get_container_type() {
        use rustwlc::*;
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        assert_eq!(root.get_container_type(), ContainerType::Container);
        {
            let wksp = root.new_child(
                Container::new_view(WlcView::root())).unwrap();
            assert_eq!(wksp.get_container_type(), ContainerType::View);
        }
        {
            let container = root.new_child(Container::Container {
                layout: Layout::Horizontal, visible: false,
                floating: false, focused: false, geometry: Geometry {
                    size: Size { w: 0, h: 0},
                    origin: Point {x: 0, y: 0}
                }
            }).unwrap();
            assert_eq!(container.get_container_type(), ContainerType::Container);
        }
    }

    #[test]
    fn get_children() {
        // Create a root with 3 children. The 3rd child has 2 children.
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        {
            let third_child = root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            third_child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
            third_child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        }
        let root_children = root.get_children();
        assert!(!root_children.is_empty(), "Root has children");
        assert_eq!(root_children.len(), 3);
        assert!(root_children.last().is_some(), "Root has final child");
        let third_child = root_children.last().expect("Asserted unwrap!");
        assert_eq!(third_child.get_children().len(), 2);
        let third_child_second_child = third_child.get_children().last()
            .expect("Asserted unwrap!");
        assert!(third_child_second_child.get_children().is_empty(),
                "Grandchild doesn't have children");
    }

    #[test]
    fn get_children_mut() {
        // Start out with one child, use get_mut_children to add grandchild.
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();

        assert!(root.get_children().last().expect("Root has child")
                .get_children().is_empty(), "Root has no grandchildren");

        {
            let mut children = root.get_children_mut();
            assert_eq!(children.len(), 1);

            let mut child = &mut children[0];
            child.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        }

        assert_eq!(root.get_children().last().expect("Asserted unwrap!")
                .get_children().len(), 1);
    }

    #[test]
    fn remove_child_at() {
        use rustwlc::handle::*;
        let mut root = Node::new(Container::new_container(FAKE_GEOMETRY));
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();
        root.new_child(Container::new_view(WlcView::root())).unwrap();
        root.new_child(Container::new_container(FAKE_GEOMETRY)).unwrap();

        let worksp = root.remove_child_at(1).expect("Index should be valid");
        assert_eq!(worksp.get_container_type(), ContainerType::View);
        assert_eq!(root.get_children().len(), 2)
    }
}
<|endoftext|>


<commit_before>use fractal::Beta;
use sqlite::{Connection, State};
use std::collections::VecDeque;
use std::rc::Rc;

use config::Config;
use {Result, Source};

pub struct Traffic {
    time: f64,
    model: Rc<Beta>,
    source: Source,
    arrivals: VecDeque<f64>,
}

impl Traffic {
    pub fn new(config: &Config, source: &Source) -> Result<Traffic> {
        let path = path!(config, "a workload pattern database");
        let backend = ok!(Connection::open(&path!(config, "a traffic database")));

        info!(target: "traffic", "Reading {:?}...", &path);
        let data = {
            let query = some!(config.get::<String>("query"),
                              "an SQL query for reading the traffic data");
            try!(read_interarrivals(&backend, query))
        };
        let ncoarse = match (data.len() as f64).log2().floor() {
            ncoarse if ncoarse < 1.0 => raise!("there are not enough data"),
            ncoarse => ncoarse as usize,
        };

        info!(target: "traffic", "Read {} arrivals. Fitting the model...", data.len());
        Ok(Traffic {
            time: 0.0,
            model: Rc::new(ok!(Beta::new(&data, ncoarse))),
            source: source.clone(),
            arrivals: VecDeque::new(),
        })
    }

    pub fn next(&mut self) -> Option<f64> {
        if let Err(error) = self.refill() {
            error!(target: "traffic", "Failed to refill the queue ({}).", error);
            return None;
        }
        self.arrivals.pop_front()
    }

    fn refill(&mut self) -> Result<()> {
        if self.arrivals.is_empty() {
            info!(target: "traffic", "Refilling the queue...");
            for step in ok!(self.model.sample(&mut self.source)) {
                self.time += step;
                self.arrivals.push_back(self.time);
            }
            info!(target: "traffic", "The queue contains {} arrivals.", self.arrivals.len());
        }
        Ok(())
    }
}

fn read_interarrivals(backend: &Connection, query: &str) -> Result<Vec<f64>> {
    let mut statement = ok!(backend.prepare(query));

    let mut data = Vec::new();
    let mut last_time = {
        if State::Row != ok!(statement.step()) {
            return Ok(data);
        }
        ok!(statement.read::<f64>(0))
    };
    while State::Row == ok!(statement.step()) {
        let time = ok!(statement.read::<f64>(0));
        data.push(time - last_time);
        last_time = time;
    }

    Ok(data)
}

#[cfg(test)]
mod tests {
    use sqlite::Connection;

    #[test]
    fn read_interarrivals() {
        let backend = Connection::open("tests/fixtures/google.sqlite3").unwrap();
        let data = super::read_interarrivals(&backend, "
            SELECT 1e-6 * `time` FROM `job_events`
            WHERE `time` IS NOT 0 AND `event type` IS 0
            ORDER BY `time` ASC;
        ").ok().unwrap();
        assert_eq!(data.len(), 667926);
    }
}
<commit_msg>traffic: remove an unused Rc<commit_after>use fractal::Beta;
use sqlite::{Connection, State};
use std::collections::VecDeque;

use config::Config;
use {Result, Source};

pub struct Traffic {
    time: f64,
    model: Beta,
    source: Source,
    arrivals: VecDeque<f64>,
}

impl Traffic {
    pub fn new(config: &Config, source: &Source) -> Result<Traffic> {
        let path = path!(config, "a workload pattern database");
        let backend = ok!(Connection::open(&path!(config, "a traffic database")));

        info!(target: "traffic", "Reading {:?}...", &path);
        let data = {
            let query = some!(config.get::<String>("query"),
                              "an SQL query for reading the traffic data");
            try!(read_interarrivals(&backend, query))
        };
        let ncoarse = match (data.len() as f64).log2().floor() {
            ncoarse if ncoarse < 1.0 => raise!("there are not enough data"),
            ncoarse => ncoarse as usize,
        };

        info!(target: "traffic", "Read {} arrivals. Fitting the model...", data.len());
        Ok(Traffic {
            time: 0.0,
            model: ok!(Beta::new(&data, ncoarse)),
            source: source.clone(),
            arrivals: VecDeque::new(),
        })
    }

    pub fn next(&mut self) -> Option<f64> {
        if let Err(error) = self.refill() {
            error!(target: "traffic", "Failed to refill the queue ({}).", error);
            return None;
        }
        self.arrivals.pop_front()
    }

    fn refill(&mut self) -> Result<()> {
        if self.arrivals.is_empty() {
            info!(target: "traffic", "Refilling the queue...");
            for step in ok!(self.model.sample(&mut self.source)) {
                self.time += step;
                self.arrivals.push_back(self.time);
            }
            info!(target: "traffic", "The queue contains {} arrivals.", self.arrivals.len());
        }
        Ok(())
    }
}

fn read_interarrivals(backend: &Connection, query: &str) -> Result<Vec<f64>> {
    let mut statement = ok!(backend.prepare(query));

    let mut data = Vec::new();
    let mut last_time = {
        if State::Row != ok!(statement.step()) {
            return Ok(data);
        }
        ok!(statement.read::<f64>(0))
    };
    while State::Row == ok!(statement.step()) {
        let time = ok!(statement.read::<f64>(0));
        data.push(time - last_time);
        last_time = time;
    }

    Ok(data)
}

#[cfg(test)]
mod tests {
    use sqlite::Connection;

    #[test]
    fn read_interarrivals() {
        let backend = Connection::open("tests/fixtures/google.sqlite3").unwrap();
        let data = super::read_interarrivals(&backend, "
            SELECT 1e-6 * `time` FROM `job_events`
            WHERE `time` IS NOT 0 AND `event type` IS 0
            ORDER BY `time` ASC;
        ").ok().unwrap();
        assert_eq!(data.len(), 667926);
    }
}
<|endoftext|>


<commit_before>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Returns the contained value or computes it from a closure.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let k = 10;
    /// assert_eq!(Value(4).unwrap_or_else(|| 2 * k), 4);
    /// assert_eq!(Absent.unwrap_or_else(|| 2 * k), 20);
    /// ```
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
        match self {
            Optional::Value(x) => x,
            Optional::Absent => f()
        }
    }

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }

}
<commit_msg>spaceapi: Add unwrap to Optional<commit_after>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Moves the value `v` out of the `Optional<T>` if it is `Value(v)`.
    ///
    /// # Panics
    ///
    /// Panics if the self value equals `Absent`.
    ///
    /// # Safety note
    ///
    /// In general, because this function may panic, its use is discouraged.
    /// Instead, prefer to use pattern matching and handle the `Absent`
    /// case explicitly.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x = Value("air");
    /// assert_eq!(x.unwrap(), "air");
    /// ```
    ///
    /// ```{.should_panic}
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<&str> = Absent;
    /// assert_eq!(x.unwrap(), "air"); // fails
    /// ```
    pub fn unwrap(self) -> T {
        match self {
            Optional::Value(val) => val,
            Optional::Absent => panic!("called `Optional::unwrap()` on a `Absent` value"),
        }
    }

    /// Returns the contained value or computes it from a closure.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let k = 10;
    /// assert_eq!(Value(4).unwrap_or_else(|| 2 * k), 4);
    /// assert_eq!(Absent.unwrap_or_else(|| 2 * k), 20);
    /// ```
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
        match self {
            Optional::Value(x) => x,
            Optional::Absent => f()
        }
    }

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }

}
<|endoftext|>


<commit_before>#![stable(feature = "", since = "1.30.0")]

#![allow(non_camel_case_types)]

//! Utilities related to FFI bindings.

use ::fmt;

/// Equivalent to C's `void` type when used as a [pointer].
///
/// In essence, `*const c_void` is equivalent to C's `const void*`
/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
/// *not* the same as C's `void` return type, which is Rust's `()` type.
///
/// Ideally, this type would be equivalent to [`!`], but currently it may
/// be more ideal to use `c_void` for FFI purposes.
///
/// [`!`]: ../../std/primitive.never.html
/// [pointer]: ../../std/primitive.pointer.html
// N.B., for LLVM to recognize the void pointer type and by extension
//     functions like malloc(), we need to have it represented as i8* in
//     LLVM bitcode. The enum used here ensures this and prevents misuse
//     of the "raw" type by only having private variants.. We need two
//     variants, because the compiler complains about the repr attribute
//     otherwise.
#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
pub enum c_void {
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant1,
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant2,
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("c_void")
    }
}

/// Basic implementation of a `va_list`.
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          all(target_arch = "aarch4", target_os = "ios"),
          windows))]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
extern {
    type VaListImpl;
}

#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          windows))]
impl fmt::Debug for VaListImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "va_list* {:p}", self)
    }
}

/// AArch64 ABI implementation of a `va_list`. See the
/// [Aarch64 Procedure Call Standard] for more details.
///
/// [AArch64 Procedure Call Standard]:
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
#[cfg(all(target_arch = "aarch64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    stack: *mut (),
    gr_top: *mut (),
    vr_top: *mut (),
    gr_offs: i32,
    vr_offs: i32,
}

/// PowerPC ABI implementation of a `va_list`.
#[cfg(all(target_arch = "powerpc", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gpr: u8,
    fpr: u8,
    reserved: u16,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// x86_64 ABI implementation of a `va_list`.
#[cfg(all(target_arch = "x86_64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gp_offset: i32,
    fp_offset: i32,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// A wrapper for a `va_list`
#[lang = "va_list"]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
#[repr(transparent)]
pub struct VaList<'a>(&'a mut VaListImpl);

// The VaArgSafe trait needs to be used in public interfaces, however, the trait
// itself must not be allowed to be used outside this module. Allowing users to
// implement the trait for a new type (thereby allowing the va_arg intrinsic to
// be used on a new type) is likely to cause undefined behavior.
//
// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
// but also ensure it cannot be used elsewhere, the trait needs to be public
// within a private module. Once RFC 2145 has been implemented look into
// improving this.
mod sealed_trait {
    /// Trait which whitelists the allowed types to be used with [VaList::arg]
    ///
    /// [VaList::va_arg]: struct.VaList.html#method.arg
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub trait VaArgSafe {}
}

macro_rules! impl_va_arg_safe {
    ($($t:ty),+) => {
        $(
            #[unstable(feature = "c_variadic",
                       reason = "the `c_variadic` feature has not been properly tested on \
                                 all supported platforms",
                       issue = "27745")]
            impl sealed_trait::VaArgSafe for $t {}
        )+
    }
}

impl_va_arg_safe!{i8, i16, i32, i64, usize}
impl_va_arg_safe!{u8, u16, u32, u64, isize}
impl_va_arg_safe!{f64}

#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *mut T {}
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *const T {}

impl<'a> VaList<'a> {
    /// Advance to the next arg.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
        va_arg(self)
    }

    /// Copy the `va_list` at the current location.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn copy<F, R>(&mut self, f: F) -> R
            where F: for<'copy> FnOnce(VaList<'copy>) -> R {
        #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                      not(target_arch = "x86_64")),
                  all(target_arch = "aarch4", target_os = "ios"),
                  windows))]
        let mut ap = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap_inner = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap = VaList(&mut ap_inner);
        let ret = f(VaList(ap.0));
        va_end(&mut ap);
        ret
    }
}

extern "rust-intrinsic" {
    /// Destroy the arglist `ap` after initialization with `va_start` or
    /// `va_copy`.
    fn va_end(ap: &mut VaList);

    /// Copy the current location of arglist `src` to the arglist `dst`.
    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              windows))]
    fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>;
    #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
              not(windows)))]
    fn va_copy(src: &VaList) -> VaListImpl;

    /// Loads an argument of type `T` from the `va_list` `ap` and increment the
    /// argument `ap` points to.
    fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaList) -> T;
}
<commit_msg>Rollup merge of #57311 - dlrobertson:fix_valist_copy, r=KodrAus<commit_after>#![stable(feature = "", since = "1.30.0")]

#![allow(non_camel_case_types)]

//! Utilities related to FFI bindings.

use ::fmt;

/// Equivalent to C's `void` type when used as a [pointer].
///
/// In essence, `*const c_void` is equivalent to C's `const void*`
/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
/// *not* the same as C's `void` return type, which is Rust's `()` type.
///
/// Ideally, this type would be equivalent to [`!`], but currently it may
/// be more ideal to use `c_void` for FFI purposes.
///
/// [`!`]: ../../std/primitive.never.html
/// [pointer]: ../../std/primitive.pointer.html
// N.B., for LLVM to recognize the void pointer type and by extension
//     functions like malloc(), we need to have it represented as i8* in
//     LLVM bitcode. The enum used here ensures this and prevents misuse
//     of the "raw" type by only having private variants.. We need two
//     variants, because the compiler complains about the repr attribute
//     otherwise.
#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
pub enum c_void {
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant1,
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant2,
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("c_void")
    }
}

/// Basic implementation of a `va_list`.
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          all(target_arch = "aarch4", target_os = "ios"),
          windows))]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
extern {
    type VaListImpl;
}

#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
              not(target_arch = "x86_64")),
          windows))]
impl fmt::Debug for VaListImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "va_list* {:p}", self)
    }
}

/// AArch64 ABI implementation of a `va_list`. See the
/// [Aarch64 Procedure Call Standard] for more details.
///
/// [AArch64 Procedure Call Standard]:
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
#[cfg(all(target_arch = "aarch64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    stack: *mut (),
    gr_top: *mut (),
    vr_top: *mut (),
    gr_offs: i32,
    vr_offs: i32,
}

/// PowerPC ABI implementation of a `va_list`.
#[cfg(all(target_arch = "powerpc", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gpr: u8,
    fpr: u8,
    reserved: u16,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// x86_64 ABI implementation of a `va_list`.
#[cfg(all(target_arch = "x86_64", not(windows)))]
#[repr(C)]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
struct VaListImpl {
    gp_offset: i32,
    fp_offset: i32,
    overflow_arg_area: *mut (),
    reg_save_area: *mut (),
}

/// A wrapper for a `va_list`
#[lang = "va_list"]
#[derive(Debug)]
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
#[repr(transparent)]
pub struct VaList<'a>(&'a mut VaListImpl);

// The VaArgSafe trait needs to be used in public interfaces, however, the trait
// itself must not be allowed to be used outside this module. Allowing users to
// implement the trait for a new type (thereby allowing the va_arg intrinsic to
// be used on a new type) is likely to cause undefined behavior.
//
// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
// but also ensure it cannot be used elsewhere, the trait needs to be public
// within a private module. Once RFC 2145 has been implemented look into
// improving this.
mod sealed_trait {
    /// Trait which whitelists the allowed types to be used with [VaList::arg]
    ///
    /// [VaList::va_arg]: struct.VaList.html#method.arg
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub trait VaArgSafe {}
}

macro_rules! impl_va_arg_safe {
    ($($t:ty),+) => {
        $(
            #[unstable(feature = "c_variadic",
                       reason = "the `c_variadic` feature has not been properly tested on \
                                 all supported platforms",
                       issue = "27745")]
            impl sealed_trait::VaArgSafe for $t {}
        )+
    }
}

impl_va_arg_safe!{i8, i16, i32, i64, usize}
impl_va_arg_safe!{u8, u16, u32, u64, isize}
impl_va_arg_safe!{f64}

#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *mut T {}
#[unstable(feature = "c_variadic",
           reason = "the `c_variadic` feature has not been properly tested on \
                     all supported platforms",
           issue = "27745")]
impl<T> sealed_trait::VaArgSafe for *const T {}

impl<'a> VaList<'a> {
    /// Advance to the next arg.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
        va_arg(self)
    }

    /// Copy the `va_list` at the current location.
    #[unstable(feature = "c_variadic",
               reason = "the `c_variadic` feature has not been properly tested on \
                         all supported platforms",
               issue = "27745")]
    pub unsafe fn copy<F, R>(&self, f: F) -> R
            where F: for<'copy> FnOnce(VaList<'copy>) -> R {
        #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                      not(target_arch = "x86_64")),
                  all(target_arch = "aarch4", target_os = "ios"),
                  windows))]
        let mut ap = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap_inner = va_copy(self);
        #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
                  not(windows)))]
        let mut ap = VaList(&mut ap_inner);
        let ret = f(VaList(ap.0));
        va_end(&mut ap);
        ret
    }
}

extern "rust-intrinsic" {
    /// Destroy the arglist `ap` after initialization with `va_start` or
    /// `va_copy`.
    fn va_end(ap: &mut VaList);

    /// Copy the current location of arglist `src` to the arglist `dst`.
    #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
                  not(target_arch = "x86_64")),
              windows))]
    fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>;
    #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"),
              not(windows)))]
    fn va_copy(src: &VaList) -> VaListImpl;

    /// Loads an argument of type `T` from the `va_list` `ap` and increment the
    /// argument `ap` points to.
    fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaList) -> T;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use app::App;
use app::Msg::CreateWindow;
use webview::Msg::PageOpen;
use url::{Url, Position};
use urls::{offset};

impl App {
    /// Open the given URL in the web view.
    pub fn open(&self, url: &str) {
        let url = self.transform_url(url);
        self.webview.emit(PageOpen(url));
    }

    /// Open the given URL in a new window.
    pub fn open_in_new_window(&mut self, url: &str) {
        let url = self.transform_url(url);
        self.model.relm.stream().emit(CreateWindow(url));
    }

    /// Open in a new window the url from the system clipboard.
    pub fn win_paste_url(&mut self) {
        if let Some(url) = self.get_url_from_clipboard() {
            self.open_in_new_window(&url);
        }
    }

    /// Go up one directory in url
    pub fn go_parent_directory(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Ok(base_url) = Url::parse(url) {

                // #TODO: go up nth directories
                if let Ok(parent) = base_url.join("../") {
                    self.open(parent.as_str());
                }
            }
        }
    }

    /// Go to the root directory or url hostname
    pub fn go_root_directory(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Ok(base_url) = Url::parse(url) {
                let root = &base_url[..Position::BeforePath];

                // #TODO: Test on file:/// and edge cases
                if !root.is_empty() {
                    self.open(root);
                }
            }
        }
    }

    pub fn url_increment(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Some(url) = offset(url, 1) {
                self.open(&url);
            }
        }
    }

    pub fn url_decrement(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Some(url) = offset(url, -1) {
                self.open(&url);
            }
        }
    }
}
<commit_msg>fix for GoParentDirectory<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use app::App;
use app::Msg::CreateWindow;
use webview::Msg::PageOpen;
use url::{Url, Position};
use urls::{offset, get_filename};

impl App {
    /// Open the given URL in the web view.
    pub fn open(&self, url: &str) {
        let url = self.transform_url(url);
        self.webview.emit(PageOpen(url));
    }

    /// Open the given URL in a new window.
    pub fn open_in_new_window(&mut self, url: &str) {
        let url = self.transform_url(url);
        self.model.relm.stream().emit(CreateWindow(url));
    }

    /// Open in a new window the url from the system clipboard.
    pub fn win_paste_url(&mut self) {
        if let Some(url) = self.get_url_from_clipboard() {
            self.open_in_new_window(&url);
        }
    }

    /// Go up one directory in url
    pub fn go_parent_directory(&self) {
        let mut parent = String::new();

        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Some(filename) = get_filename(url) {
                if filename.is_empty() {
                    if let Ok(base_url) = Url::parse(url) {
                        parent = base_url.join("../").unwrap().to_string();
                    }
                } else {
                    parent = url[..url.len()-filename.len()].to_string();
                }
            }

            if !parent.is_empty() {
                self.open(&parent);
            }
        }
    }

    /// Go to the root directory or url hostname
    pub fn go_root_directory(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Ok(base_url) = Url::parse(url) {
                let root = &base_url[..Position::BeforePath];

                // #TODO: Test on file:/// and edge cases
                if !root.is_empty() {
                    self.open(root);
                }
            }
        }
    }

    pub fn url_increment(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Some(url) = offset(url, 1) {
                self.open(&url);
            }
        }
    }

    pub fn url_decrement(&self) {
        if let Some(ref url) = self.webview.widget().get_uri() {
            if let Some(url) = offset(url, -1) {
                self.open(&url);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use dirs;

/// OS specific path to the application cache directory.
pub fn cache(app_name: &str) -> Option<PathBuf>
{
   if app_name.is_empty() {
      return None;
   }

   cache_home().map(|mut dir| { dir.push(app_name); dir })
}

/// OS specific path for caches.
pub fn cache_home() -> Option<PathBuf>
{
   #[cfg(unix)]
   fn _cache_home() -> Option<PathBuf>
   {
      dirs::home_dir().map(|mut dir| { dir.push(".cache"); dir })
   }

   #[cfg(windows)]
   fn _cache_home() -> Option<PathBuf>
   {
      dirs::home_dir().map(|mut dir| {
         dir.push("Local Settings");
         dir.push("Cache");
         dir
      })
   }

   _cache_home()
}

#[test]
#[cfg(test)]
fn tests()
{
   #[cfg(unix)]
   fn _tests()
   {
      match home_dir() {
         Some(mut dir) => {
            dir.push(".cache");
            dir.push("blub");
            let dir_str = format!("{}", dir.display());
            let cache_str = format!("{}", cache("blub").unwrap().display());
            assert_eq!(dir_str, cache_str);
         }

         None => assert!(false, "Couldn't get homedir!")
      }
   }

   _tests()
}
<commit_msg>Fix compile error<commit_after>use std::path::PathBuf;
use dirs;

/// OS specific path to the application cache directory.
pub fn cache(app_name: &str) -> Option<PathBuf>
{
   if app_name.is_empty() {
      return None;
   }

   cache_home().map(|mut dir| { dir.push(app_name); dir })
}

/// OS specific path for caches.
pub fn cache_home() -> Option<PathBuf>
{
   #[cfg(unix)]
   fn _cache_home() -> Option<PathBuf>
   {
      dirs::home_dir().map(|mut dir| { dir.push(".cache"); dir })
   }

   #[cfg(windows)]
   fn _cache_home() -> Option<PathBuf>
   {
      dirs::home_dir().map(|mut dir| {
         dir.push("Local Settings");
         dir.push("Cache");
         dir
      })
   }

   _cache_home()
}

#[test]
#[cfg(test)]
fn tests()
{
   #[cfg(unix)]
   fn _tests()
   {
      match dirs::home_dir() {
         Some(mut dir) => {
            dir.push(".cache");
            dir.push("blub");
            let dir_str = format!("{}", dir.display());
            let cache_str = format!("{}", cache("blub").unwrap().display());
            assert_eq!(dir_str, cache_str);
         }

         None => assert!(false, "Couldn't get homedir!")
      }
   }

   _tests()
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `bool` module contains useful code to help work with boolean values.

A quick summary:

## Trait implementations for `bool`

Implementations of the following traits:

* `FromStr`
* `Ord`
* `TotalOrd`
* `Eq`

## Various functions to compare `bool`s

All of the standard comparison functions one would expect: `and`, `eq`, `or`,
and more.

Also, a few conversion functions: `to_bit` and `to_str`.

Finally, some inquries into the nature of truth: `is_true` and `is_false`.

*/

#[cfg(not(test))]
use cmp::{Eq, Ord, TotalOrd, Ordering};
use option::{None, Option, Some};
use from_str::FromStr;
use to_str::ToStr;

/**
* Negation of a boolean value.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::not(true)
* false
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::not(false)
* true
* ~~~
*/
pub fn not(v: bool) -> bool { !v }

/**
* Conjunction of two boolean values.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::and(true, false)
* false
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::and(true, true)
* true
* ~~~
*/
pub fn and(a: bool, b: bool) -> bool { a && b }

/**
* Disjunction of two boolean values.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::or(true, false)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::or(false, false)
* false
* ~~~
*/
pub fn or(a: bool, b: bool) -> bool { a || b }

/**
* An 'exclusive or' of two boolean values.
*
* 'exclusive or' is identical to `or(and(a, not(b)), and(not(a), b))`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::xor(true, false)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::xor(true, true)
* false
* ~~~
*/
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

/**
* Implication between two boolean values.
*
* Implication is often phrased as 'if a then b.'
*
* 'if a then b' is equivalent to `!a || b`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::implies(true, true)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::implies(true, false)
* false
* ~~~
*/
pub fn implies(a: bool, b: bool) -> bool { !a || b }

/**
* Is a given boolean value true?
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::is_true(true)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::is_true(false)
* false
* ~~~
*/
pub fn is_true(v: bool) -> bool { v }

/**
* Is a given boolean value false?
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::is_false(false)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::is_false(true)
* false
* ~~~
*/
pub fn is_false(v: bool) -> bool { !v }

/**
* Parse a `bool` from a `str`.
*
* Yields an `Option<bool>`, because `str` may or may not actually be parseable.
*
* # Examples
*
* ~~~ {.rust}
* rusti> FromStr::from_str::<bool>("true")
* Some(true)
* ~~~
*
* ~~~ {.rust}
* rusti> FromStr::from_str::<bool>("false")
* Some(false)
* ~~~
*
* ~~~ {.rust}
* rusti> FromStr::from_str::<bool>("not even a boolean")
* None
* ~~~
*/
impl FromStr for bool {
    fn from_str(s: &str) -> Option<bool> {
        match s {
            "true"  => Some(true),
            "false" => Some(false),
            _       => None,
        }
    }
}

/**
* Convert a `bool` to a `str`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> true.to_str()
* "true"
* ~~~
*
* ~~~ {.rust}
* rusti> false.to_str()
* "false"
* ~~~
*/
impl ToStr for bool {
    #[inline]
    fn to_str(&self) -> ~str {
        if *self { ~"true" } else { ~"false" }
    }
}

/**
* Iterates over all truth values, passing them to the given block.
*
* There are no guarantees about the order values will be given.
*
* # Examples
* ~~~
* do std::bool::all_values |x: bool| {
*     println(x.to_str())
* }
* ~~~
*/
pub fn all_values(blk: &fn(v: bool)) {
    blk(true);
    blk(false);
}

/**
* Convert a `bool` to a `u8`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::to_bit(true)
* 1
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::to_bit(false)
* 0
* ~~~
*/
#[inline]
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

#[cfg(not(test))]
impl Ord for bool {
    #[inline]
    fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) }
    #[inline]
    fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) }
    #[inline]
    fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) }
    #[inline]
    fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) }
}

#[cfg(not(test))]
impl TotalOrd for bool {
    #[inline]
    fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) }
}

/**
* Equality between two boolean values.
*
* Two booleans are equal if they have the same value.
*
* ~~~ {.rust}
* rusti> false.eq(&true)
* false
* ~~~
*
* ~~~ {.rust}
* rusti> false == false
* true
* ~~~
*
* ~~~ {.rust}
* rusti> false != true
* true
* ~~~
*
* ~~~ {.rust}
* rusti> false.ne(&false)
* false
* ~~~
*/
#[cfg(not(test))]
impl Eq for bool {
    #[inline]
    fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
    #[inline]
    fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}

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

    #[test]
    fn test_bool_from_str() {
        do all_values |v| {
            assert!(Some(v) == FromStr::from_str(v.to_str()))
        }
    }

    #[test]
    fn test_bool_to_str() {
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(true.to_str(), ~"true");
    }

    #[test]
    fn test_bool_to_bit() {
        do all_values |v| {
            assert_eq!(to_bit(v), if is_true(v) { 1u8 } else { 0u8 });
        }
    }

    #[test]
    fn test_bool_ord() {
        assert!(true > false);
        assert!(!(false > true));

        assert!(false < true);
        assert!(!(true < false));

        assert!(false <= false);
        assert!(false >= false);
        assert!(true <= true);
        assert!(true >= true);

        assert!(false <= true);
        assert!(!(false >= true));
        assert!(true >= false);
        assert!(!(true <= false));
    }

    #[test]
    fn test_bool_totalord() {
        assert_eq!(true.cmp(&true), Equal);
        assert_eq!(false.cmp(&false), Equal);
        assert_eq!(true.cmp(&false), Greater);
        assert_eq!(false.cmp(&true), Less);
    }
}
<commit_msg>Impl Not for bool<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `bool` module contains useful code to help work with boolean values.

A quick summary:

## Trait implementations for `bool`

Implementations of the following traits:

* `FromStr`
* `ToStr`
* `Not`
* `Ord`
* `TotalOrd`
* `Eq`

## Various functions to compare `bool`s

All of the standard comparison functions one would expect: `and`, `eq`, `or`,
and more.

Also, a few conversion functions: `to_bit` and `to_str`.

Finally, some inquries into the nature of truth: `is_true` and `is_false`.

*/

#[cfg(not(test))]
use cmp::{Eq, Ord, TotalOrd, Ordering};
#[cfg(not(test))]
use ops::Not;
use option::{None, Option, Some};
use from_str::FromStr;
use to_str::ToStr;

/**
* Negation of a boolean value.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::not(true)
* false
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::not(false)
* true
* ~~~
*/
pub fn not(v: bool) -> bool { !v }

/**
* Conjunction of two boolean values.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::and(true, false)
* false
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::and(true, true)
* true
* ~~~
*/
pub fn and(a: bool, b: bool) -> bool { a && b }

/**
* Disjunction of two boolean values.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::or(true, false)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::or(false, false)
* false
* ~~~
*/
pub fn or(a: bool, b: bool) -> bool { a || b }

/**
* An 'exclusive or' of two boolean values.
*
* 'exclusive or' is identical to `or(and(a, not(b)), and(not(a), b))`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::xor(true, false)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::xor(true, true)
* false
* ~~~
*/
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

/**
* Implication between two boolean values.
*
* Implication is often phrased as 'if a then b.'
*
* 'if a then b' is equivalent to `!a || b`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::implies(true, true)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::implies(true, false)
* false
* ~~~
*/
pub fn implies(a: bool, b: bool) -> bool { !a || b }

/**
* Is a given boolean value true?
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::is_true(true)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::is_true(false)
* false
* ~~~
*/
pub fn is_true(v: bool) -> bool { v }

/**
* Is a given boolean value false?
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::is_false(false)
* true
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::is_false(true)
* false
* ~~~
*/
pub fn is_false(v: bool) -> bool { !v }

/**
* Parse a `bool` from a `str`.
*
* Yields an `Option<bool>`, because `str` may or may not actually be parseable.
*
* # Examples
*
* ~~~ {.rust}
* rusti> FromStr::from_str::<bool>("true")
* Some(true)
* ~~~
*
* ~~~ {.rust}
* rusti> FromStr::from_str::<bool>("false")
* Some(false)
* ~~~
*
* ~~~ {.rust}
* rusti> FromStr::from_str::<bool>("not even a boolean")
* None
* ~~~
*/
impl FromStr for bool {
    fn from_str(s: &str) -> Option<bool> {
        match s {
            "true"  => Some(true),
            "false" => Some(false),
            _       => None,
        }
    }
}

/**
* Convert a `bool` to a `str`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> true.to_str()
* "true"
* ~~~
*
* ~~~ {.rust}
* rusti> false.to_str()
* "false"
* ~~~
*/
impl ToStr for bool {
    #[inline]
    fn to_str(&self) -> ~str {
        if *self { ~"true" } else { ~"false" }
    }
}

/**
* Iterates over all truth values, passing them to the given block.
*
* There are no guarantees about the order values will be given.
*
* # Examples
* ~~~
* do std::bool::all_values |x: bool| {
*     println(x.to_str())
* }
* ~~~
*/
pub fn all_values(blk: &fn(v: bool)) {
    blk(true);
    blk(false);
}

/**
* Convert a `bool` to a `u8`.
*
* # Examples
*
* ~~~ {.rust}
* rusti> std::bool::to_bit(true)
* 1
* ~~~
*
* ~~~ {.rust}
* rusti> std::bool::to_bit(false)
* 0
* ~~~
*/
#[inline]
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

/**
* The logical complement of a boolean value.
*
* # Examples
*
* ~~~rust
* rusti> !true
* false
* ~~~
*
* ~~~rust
* rusti> !false
* true
* ~~~
*/
#[cfg(not(test))]
impl Not<bool> for bool {
    #[inline]
    fn not(&self) -> bool { !*self }
}

#[cfg(not(test))]
impl Ord for bool {
    #[inline]
    fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) }
    #[inline]
    fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) }
    #[inline]
    fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) }
    #[inline]
    fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) }
}

#[cfg(not(test))]
impl TotalOrd for bool {
    #[inline]
    fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) }
}

/**
* Equality between two boolean values.
*
* Two booleans are equal if they have the same value.
*
* ~~~ {.rust}
* rusti> false.eq(&true)
* false
* ~~~
*
* ~~~ {.rust}
* rusti> false == false
* true
* ~~~
*
* ~~~ {.rust}
* rusti> false != true
* true
* ~~~
*
* ~~~ {.rust}
* rusti> false.ne(&false)
* false
* ~~~
*/
#[cfg(not(test))]
impl Eq for bool {
    #[inline]
    fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
    #[inline]
    fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}

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

    #[test]
    fn test_bool_from_str() {
        do all_values |v| {
            assert!(Some(v) == FromStr::from_str(v.to_str()))
        }
    }

    #[test]
    fn test_bool_to_str() {
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(true.to_str(), ~"true");
    }

    #[test]
    fn test_bool_to_bit() {
        do all_values |v| {
            assert_eq!(to_bit(v), if is_true(v) { 1u8 } else { 0u8 });
        }
    }

    #[test]
    fn test_bool_ord() {
        assert!(true > false);
        assert!(!(false > true));

        assert!(false < true);
        assert!(!(true < false));

        assert!(false <= false);
        assert!(false >= false);
        assert!(true <= true);
        assert!(true >= true);

        assert!(false <= true);
        assert!(!(false >= true));
        assert!(true >= false);
        assert!(!(true <= false));
    }

    #[test]
    fn test_bool_totalord() {
        assert_eq!(true.cmp(&true), Equal);
        assert_eq!(false.cmp(&false), Equal);
        assert_eq!(true.cmp(&false), Greater);
        assert_eq!(false.cmp(&true), Less);
    }
}
<|endoftext|>