<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/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

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

use chrono::{DateTime, Utc};

use devicemapper::{Device, Sectors};

use crate::{
    engine::{
        strat_engine::{
            backstore::{blockdev::StratBlockDev, metadata::BDA, shared::BlockDevPath},
            device::blkdev_size,
            serde_structs::{BackstoreSave, BaseBlockDevSave, PoolSave},
        },
        types::{BlockDevTier, DevUuid, PoolUuid},
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
///
/// Precondition: All devices represented by devnodes have been already
/// identified as having the given pool UUID and their associated device
/// UUID. Thus, it is an error if the BDA's information does not match that
/// already known. It is also an error if the BDA can not be read at all
/// as that BDA may belong to the device with the most recently written
/// metadata.
pub fn get_metadata(
    pool_uuid: PoolUuid,
    devnodes: &HashMap<Device, (DevUuid, PathBuf)>,
) -> StratisResult<Option<(DateTime<Utc>, PoolSave)>> {
    let mut bdas = Vec::new();
    for (device_uuid, devnode) in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new()
                            .read(true)
                            .open(devnode)?)?
            .ok_or_else(||
                        StratisError::Error(format!(
                                "Failed to read BDA from device {} which has previously been identified as a Stratis device with pool UUID {} and device UUID {}",
                                devnode.display(),
                                pool_uuid.to_simple_ref(),
                                device_uuid.to_simple_ref())))?;
        if bda.pool_uuid() != pool_uuid || bda.dev_uuid() != *device_uuid {
            return Err(StratisError::Error(format!(
                        "BDA identifiers (pool UUID: {}, device UUID: {}) for device {} do not agree with previously read identifiers (pool UUID: {}, device UUID: {})",
                        bda.pool_uuid().to_simple_ref(),
                        bda.dev_uuid().to_simple_ref(),
                        devnode.display(),
                        pool_uuid.to_simple_ref(),
                        device_uuid.to_simple_ref()
                        )));
        };
        bdas.push((devnode, bda));
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas
            .iter()
            .filter_map(|&(_, ref bda)| bda.last_update_time())
            .max()
        {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    bdas.iter()
        .filter_map(|&(devnode, ref bda)| {
            if bda.last_update_time() == Some(most_recent_time) {
                OpenOptions::new()
                    .read(true)
                    .open(devnode)
                    .ok()
                    .and_then(|mut f| bda.load_state(&mut f).unwrap_or(None))
                    .and_then(|data| serde_json::from_slice(&data).ok())
            } else {
                None
            }
        })
        .next()
        .ok_or_else(|| {
            StratisError::Engine(
                ErrorEnum::NotFound,
                "timestamp indicates data was written, but no data successfully read".into(),
            )
        })
        .map(|psave| Some((*most_recent_time, psave)))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices. Sort the blockdevs in the order in which they were
/// recorded in the metadata.
/// Returns an error if a BDA can not be read or can not be found on any
/// blockdev in devnodes.
/// Returns an error if the blockdevs obtained do not match the metadata.
/// Returns a tuple, of which the first are the data devs, and the second
/// are the devs that support the cache tier.
/// Precondition: Every device in devnodes has already been determined to
/// belong to the pool with the specified pool uuid.
pub fn get_blockdevs(
    pool_uuid: PoolUuid,
    backstore_save: &BackstoreSave,
    devnodes: &HashMap<Device, (DevUuid, PathBuf)>,
) -> StratisResult<(Vec<StratBlockDev>, Vec<StratBlockDev>)> {
    let recorded_data_map: HashMap<DevUuid, (usize, &BaseBlockDevSave)> = backstore_save
        .data_tier
        .blockdev
        .devs
        .iter()
        .enumerate()
        .map(|(i, bds)| (bds.uuid, (i, bds)))
        .collect();

    let recorded_cache_map: HashMap<DevUuid, (usize, &BaseBlockDevSave)> =
        match backstore_save.cache_tier {
            Some(ref cache_tier) => cache_tier
                .blockdev
                .devs
                .iter()
                .enumerate()
                .map(|(i, bds)| (bds.uuid, (i, bds)))
                .collect(),
            None => HashMap::new(),
        };

    let mut segment_table: HashMap<DevUuid, Vec<(Sectors, Sectors)>> = HashMap::new();
    for seg in &backstore_save.data_tier.blockdev.allocs[0] {
        segment_table
            .entry(seg.parent)
            .or_insert_with(Vec::default)
            .push((seg.start, seg.length))
    }

    if let Some(ref cache_tier) = backstore_save.cache_tier {
        for seg in cache_tier.blockdev.allocs.iter().flat_map(|i| i.iter()) {
            segment_table
                .entry(seg.parent)
                .or_insert_with(Vec::default)
                .push((seg.start, seg.length))
        }
    }

    // Construct a single StratBlockDev. Return the tier to which the
    // blockdev has been found to belong. Returns an error if the block
    // device has shrunk, no metadata can be found for the block device,
    // or it is impossible to set up the device because the recorded
    // allocation information is impossible.
    fn get_blockdev(
        device: Device,
        devnode: &Path,
        bda: BDA,
        data_map: &HashMap<DevUuid, (usize, &BaseBlockDevSave)>,
        cache_map: &HashMap<DevUuid, (usize, &BaseBlockDevSave)>,
        segment_table: &HashMap<DevUuid, Vec<(Sectors, Sectors)>>,
    ) -> StratisResult<(BlockDevTier, StratBlockDev)> {
        // Return an error if apparent size of Stratis block device appears to
        // have decreased since metadata was recorded or if size of block
        // device could not be obtained.
        blkdev_size(&OpenOptions::new().read(true).open(devnode)?).and_then(|actual_size| {
            let actual_size_sectors = actual_size.sectors();
            let recorded_size = bda.dev_size().sectors();
            if actual_size_sectors < recorded_size {
                let err_msg = format!(
                    "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had recorded size {}, but actual size is less at {}",
                    device,
                    devnode.display(),
                    bda.pool_uuid().to_simple_ref(),
                    bda.dev_uuid().to_simple_ref(),
                    recorded_size,
                    actual_size_sectors
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            } else {
                Ok(())
            }
        })?;

        let dev_uuid = bda.dev_uuid();

        // Locate the device in the metadata using its uuid. Return the device
        // metadata and whether it was a cache or a datadev.
        let (tier, &(_, bd_save)) = data_map
            .get(&dev_uuid)
            .map(|bd_save| (BlockDevTier::Data, bd_save))
            .or_else(|| {
                cache_map
                    .get(&dev_uuid)
                    .map(|bd_save| (BlockDevTier::Cache, bd_save))
            })
            .ok_or_else(|| {
                let err_msg = format!(
                        "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had no record in pool metadata",
                        device,
                        devnode.display(),
                        bda.pool_uuid().to_simple_ref(),
                        bda.dev_uuid().to_simple_ref()
                    );
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

        // This should always succeed since the actual size is at
        // least the recorded size, so all segments should be
        // available to be allocated. If this fails, the most likely
        // conclusion is metadata corruption.
        let segments = segment_table.get(&dev_uuid);
        Ok((
            tier,
            StratBlockDev::new(
                device,
                BlockDevPath::Unencrypted(devnode.to_owned()),
                bda,
                segments.unwrap_or(&vec![]),
                bd_save.user_info.clone(),
                bd_save.hardware_info.clone(),
                None,
            )?,
        ))
    }

    let (mut datadevs, mut cachedevs): (Vec<StratBlockDev>, Vec<StratBlockDev>) = (vec![], vec![]);
    for (device, (_, devnode)) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?.ok_or_else(|| {
            StratisError::Engine(ErrorEnum::NotFound,
                                                 format!("Device {} with devnode {} was previously determined to belong to pool with uuid {} but no BDA was found",
                                                 device,
                                                 devnode.display(),
                                                 pool_uuid.to_simple_ref()))
        })?;

        get_blockdev(
            *device,
            devnode,
            bda,
            &recorded_data_map,
            &recorded_cache_map,
            &segment_table,
        )
        .map(|(tier, blockdev)| {
            match tier {
                BlockDevTier::Data => &mut datadevs,
                BlockDevTier::Cache => &mut cachedevs,
            }
            .push(blockdev)
        })?;
    }

    // Verify that devices located are congruent with the metadata recorded
    // and generally consistent with expectations. If all seems correct,
    // sort the devices according to their order in the metadata.
    fn check_and_sort_devs(
        mut devs: Vec<StratBlockDev>,
        dev_map: &HashMap<DevUuid, (usize, &BaseBlockDevSave)>,
    ) -> StratisResult<Vec<StratBlockDev>> {
        let mut uuids = HashSet::new();
        let mut duplicate_uuids = Vec::new();
        for dev in &devs {
            let dev_uuid = dev.uuid();
            if !uuids.insert(dev_uuid) {
                duplicate_uuids.push(dev_uuid);
            }
        }

        if !duplicate_uuids.is_empty() {
            let err_msg = format!(
                "The following list of Stratis UUIDs were each claimed by more than one Stratis device: {}",
                duplicate_uuids.iter().map(|u| u.to_simple_ref().to_string()).collect::<Vec<_>>().join(", ")
            );
            return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg));
        }

        let recorded_uuids: HashSet<_> = dev_map.keys().cloned().collect();
        if uuids != recorded_uuids {
            let err_msg = format!(
                "UUIDs of devices found ({}) did not correspond with UUIDs specified in the metadata for this group of devices ({})",
                uuids.iter().map(|u| u.to_simple_ref().to_string()).collect::<Vec<_>>().join(", "),
                recorded_uuids.iter().map(|u| u.to_simple_ref().to_string()).collect::<Vec<_>>().join(", "),
            );
            return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg));
        }

        // Sort the devices according to their original location in the
        // metadata. Use a faster unstable sort, because the order of
        // devs before the sort is arbitrary and does not need to be
        // preserved.
        devs.sort_unstable_by_key(|dev| dev_map[&dev.uuid()].0);
        Ok(devs)
    }

    let datadevs = check_and_sort_devs(datadevs, &recorded_data_map)?;
    let cachedevs = check_and_sort_devs(cachedevs, &recorded_cache_map)?;

    Ok((datadevs, cachedevs))
}
<commit_msg>Add a FIXME to mark an important spot in the code base<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/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

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

use chrono::{DateTime, Utc};

use devicemapper::{Device, Sectors};

use crate::{
    engine::{
        strat_engine::{
            backstore::{blockdev::StratBlockDev, metadata::BDA, shared::BlockDevPath},
            device::blkdev_size,
            serde_structs::{BackstoreSave, BaseBlockDevSave, PoolSave},
        },
        types::{BlockDevTier, DevUuid, PoolUuid},
    },
    stratis::{ErrorEnum, StratisError, StratisResult},
};

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
///
/// Precondition: All devices represented by devnodes have been already
/// identified as having the given pool UUID and their associated device
/// UUID. Thus, it is an error if the BDA's information does not match that
/// already known. It is also an error if the BDA can not be read at all
/// as that BDA may belong to the device with the most recently written
/// metadata.
pub fn get_metadata(
    pool_uuid: PoolUuid,
    devnodes: &HashMap<Device, (DevUuid, PathBuf)>,
) -> StratisResult<Option<(DateTime<Utc>, PoolSave)>> {
    let mut bdas = Vec::new();
    for (device_uuid, devnode) in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new()
                            .read(true)
                            .open(devnode)?)?
            .ok_or_else(||
                        StratisError::Error(format!(
                                "Failed to read BDA from device {} which has previously been identified as a Stratis device with pool UUID {} and device UUID {}",
                                devnode.display(),
                                pool_uuid.to_simple_ref(),
                                device_uuid.to_simple_ref())))?;
        if bda.pool_uuid() != pool_uuid || bda.dev_uuid() != *device_uuid {
            return Err(StratisError::Error(format!(
                        "BDA identifiers (pool UUID: {}, device UUID: {}) for device {} do not agree with previously read identifiers (pool UUID: {}, device UUID: {})",
                        bda.pool_uuid().to_simple_ref(),
                        bda.dev_uuid().to_simple_ref(),
                        devnode.display(),
                        pool_uuid.to_simple_ref(),
                        device_uuid.to_simple_ref()
                        )));
        };
        bdas.push((devnode, bda));
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas
            .iter()
            .filter_map(|&(_, ref bda)| bda.last_update_time())
            .max()
        {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    bdas.iter()
        .filter_map(|&(devnode, ref bda)| {
            if bda.last_update_time() == Some(most_recent_time) {
                OpenOptions::new()
                    .read(true)
                    .open(devnode)
                    .ok()
                    .and_then(|mut f| bda.load_state(&mut f).unwrap_or(None))
                    .and_then(|data| serde_json::from_slice(&data).ok())
            } else {
                None
            }
        })
        .next()
        .ok_or_else(|| {
            StratisError::Engine(
                ErrorEnum::NotFound,
                "timestamp indicates data was written, but no data successfully read".into(),
            )
        })
        .map(|psave| Some((*most_recent_time, psave)))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices. Sort the blockdevs in the order in which they were
/// recorded in the metadata.
/// Returns an error if a BDA can not be read or can not be found on any
/// blockdev in devnodes.
/// Returns an error if the blockdevs obtained do not match the metadata.
/// Returns a tuple, of which the first are the data devs, and the second
/// are the devs that support the cache tier.
/// Precondition: Every device in devnodes has already been determined to
/// belong to the pool with the specified pool uuid.
pub fn get_blockdevs(
    pool_uuid: PoolUuid,
    backstore_save: &BackstoreSave,
    devnodes: &HashMap<Device, (DevUuid, PathBuf)>,
) -> StratisResult<(Vec<StratBlockDev>, Vec<StratBlockDev>)> {
    let recorded_data_map: HashMap<DevUuid, (usize, &BaseBlockDevSave)> = backstore_save
        .data_tier
        .blockdev
        .devs
        .iter()
        .enumerate()
        .map(|(i, bds)| (bds.uuid, (i, bds)))
        .collect();

    let recorded_cache_map: HashMap<DevUuid, (usize, &BaseBlockDevSave)> =
        match backstore_save.cache_tier {
            Some(ref cache_tier) => cache_tier
                .blockdev
                .devs
                .iter()
                .enumerate()
                .map(|(i, bds)| (bds.uuid, (i, bds)))
                .collect(),
            None => HashMap::new(),
        };

    let mut segment_table: HashMap<DevUuid, Vec<(Sectors, Sectors)>> = HashMap::new();
    for seg in &backstore_save.data_tier.blockdev.allocs[0] {
        segment_table
            .entry(seg.parent)
            .or_insert_with(Vec::default)
            .push((seg.start, seg.length))
    }

    if let Some(ref cache_tier) = backstore_save.cache_tier {
        for seg in cache_tier.blockdev.allocs.iter().flat_map(|i| i.iter()) {
            segment_table
                .entry(seg.parent)
                .or_insert_with(Vec::default)
                .push((seg.start, seg.length))
        }
    }

    // Construct a single StratBlockDev. Return the tier to which the
    // blockdev has been found to belong. Returns an error if the block
    // device has shrunk, no metadata can be found for the block device,
    // or it is impossible to set up the device because the recorded
    // allocation information is impossible.
    fn get_blockdev(
        device: Device,
        devnode: &Path,
        bda: BDA,
        data_map: &HashMap<DevUuid, (usize, &BaseBlockDevSave)>,
        cache_map: &HashMap<DevUuid, (usize, &BaseBlockDevSave)>,
        segment_table: &HashMap<DevUuid, Vec<(Sectors, Sectors)>>,
    ) -> StratisResult<(BlockDevTier, StratBlockDev)> {
        // Return an error if apparent size of Stratis block device appears to
        // have decreased since metadata was recorded or if size of block
        // device could not be obtained.
        blkdev_size(&OpenOptions::new().read(true).open(devnode)?).and_then(|actual_size| {
            let actual_size_sectors = actual_size.sectors();
            let recorded_size = bda.dev_size().sectors();
            if actual_size_sectors < recorded_size {
                let err_msg = format!(
                    "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had recorded size {}, but actual size is less at {}",
                    device,
                    devnode.display(),
                    bda.pool_uuid().to_simple_ref(),
                    bda.dev_uuid().to_simple_ref(),
                    recorded_size,
                    actual_size_sectors
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            } else {
                Ok(())
            }
        })?;

        let dev_uuid = bda.dev_uuid();

        // Locate the device in the metadata using its uuid. Return the device
        // metadata and whether it was a cache or a datadev.
        let (tier, &(_, bd_save)) = data_map
            .get(&dev_uuid)
            .map(|bd_save| (BlockDevTier::Data, bd_save))
            .or_else(|| {
                cache_map
                    .get(&dev_uuid)
                    .map(|bd_save| (BlockDevTier::Cache, bd_save))
            })
            .ok_or_else(|| {
                let err_msg = format!(
                        "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had no record in pool metadata",
                        device,
                        devnode.display(),
                        bda.pool_uuid().to_simple_ref(),
                        bda.dev_uuid().to_simple_ref()
                    );
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

        // This should always succeed since the actual size is at
        // least the recorded size, so all segments should be
        // available to be allocated. If this fails, the most likely
        // conclusion is metadata corruption.
        let segments = segment_table.get(&dev_uuid);
        Ok((
            tier,
            StratBlockDev::new(
                device,
                // FIXME: This block device could represent an encrypted or
                // an unencrypted device.
                BlockDevPath::Unencrypted(devnode.to_owned()),
                bda,
                segments.unwrap_or(&vec![]),
                bd_save.user_info.clone(),
                bd_save.hardware_info.clone(),
                None,
            )?,
        ))
    }

    let (mut datadevs, mut cachedevs): (Vec<StratBlockDev>, Vec<StratBlockDev>) = (vec![], vec![]);
    for (device, (_, devnode)) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?.ok_or_else(|| {
            StratisError::Engine(ErrorEnum::NotFound,
                                                 format!("Device {} with devnode {} was previously determined to belong to pool with uuid {} but no BDA was found",
                                                 device,
                                                 devnode.display(),
                                                 pool_uuid.to_simple_ref()))
        })?;

        get_blockdev(
            *device,
            devnode,
            bda,
            &recorded_data_map,
            &recorded_cache_map,
            &segment_table,
        )
        .map(|(tier, blockdev)| {
            match tier {
                BlockDevTier::Data => &mut datadevs,
                BlockDevTier::Cache => &mut cachedevs,
            }
            .push(blockdev)
        })?;
    }

    // Verify that devices located are congruent with the metadata recorded
    // and generally consistent with expectations. If all seems correct,
    // sort the devices according to their order in the metadata.
    fn check_and_sort_devs(
        mut devs: Vec<StratBlockDev>,
        dev_map: &HashMap<DevUuid, (usize, &BaseBlockDevSave)>,
    ) -> StratisResult<Vec<StratBlockDev>> {
        let mut uuids = HashSet::new();
        let mut duplicate_uuids = Vec::new();
        for dev in &devs {
            let dev_uuid = dev.uuid();
            if !uuids.insert(dev_uuid) {
                duplicate_uuids.push(dev_uuid);
            }
        }

        if !duplicate_uuids.is_empty() {
            let err_msg = format!(
                "The following list of Stratis UUIDs were each claimed by more than one Stratis device: {}",
                duplicate_uuids.iter().map(|u| u.to_simple_ref().to_string()).collect::<Vec<_>>().join(", ")
            );
            return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg));
        }

        let recorded_uuids: HashSet<_> = dev_map.keys().cloned().collect();
        if uuids != recorded_uuids {
            let err_msg = format!(
                "UUIDs of devices found ({}) did not correspond with UUIDs specified in the metadata for this group of devices ({})",
                uuids.iter().map(|u| u.to_simple_ref().to_string()).collect::<Vec<_>>().join(", "),
                recorded_uuids.iter().map(|u| u.to_simple_ref().to_string()).collect::<Vec<_>>().join(", "),
            );
            return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg));
        }

        // Sort the devices according to their original location in the
        // metadata. Use a faster unstable sort, because the order of
        // devs before the sort is arbitrary and does not need to be
        // preserved.
        devs.sort_unstable_by_key(|dev| dev_map[&dev.uuid()].0);
        Ok(devs)
    }

    let datadevs = check_and_sort_devs(datadevs, &recorded_data_map)?;
    let cachedevs = check_and_sort_devs(cachedevs, &recorded_cache_map)?;

    Ok((datadevs, cachedevs))
}
<|endoftext|>


<commit_before>use std::fmt;
use itertools::Itertools;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type {
    Unit,
    Bool,
    Int,
    Double,
    Char,
    LValue(Box<Type>),
    Ptr(Box<Type>),
    Function(FunctionType),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionType {
    pub return_ty: Box<Type>,
    pub params_ty: Vec<Type>,
    pub variadic: bool,
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Unit => write!(f, "()"),
            Type::Bool => write!(f, "bool"),
            Type::Int => write!(f, "int"),
            Type::Double => write!(f, "double"),
            Type::Char => write!(f, "char"),
            Type::LValue(ref sub) => write!(f, "&{}", *sub),
            Type::Ptr(ref sub) => write!(f, "*{}", *sub),
            Type::Function(ref func) => write!(f, "{}", func),
        }
    }
}

impl fmt::Display for FunctionType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "({}{}) -> {}",
               self.params_ty.iter().join(", "),
               if self.variadic { ", .." } else { "" },
               *self.return_ty)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub TypeId(usize);

pub struct TypeManager {
    pub types: Vec<Type>,
}
<commit_msg>Removed typemanager<commit_after>use std::fmt;
use itertools::Itertools;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type {
    Unit,
    Bool,
    Int,
    Double,
    Char,
    LValue(Box<Type>),
    Ptr(Box<Type>),
    Function(FunctionType),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionType {
    pub return_ty: Box<Type>,
    pub params_ty: Vec<Type>,
    pub variadic: bool,
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Unit => write!(f, "()"),
            Type::Bool => write!(f, "bool"),
            Type::Int => write!(f, "int"),
            Type::Double => write!(f, "double"),
            Type::Char => write!(f, "char"),
            Type::LValue(ref sub) => write!(f, "&{}", *sub),
            Type::Ptr(ref sub) => write!(f, "*{}", *sub),
            Type::Function(ref func) => write!(f, "{}", func),
        }
    }
}

impl fmt::Display for FunctionType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "({}{}) -> {}",
               self.params_ty.iter().join(", "),
               if self.variadic { ", .." } else { "" },
               *self.return_ty)
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Define all Reserved Addresses.
// # Builtin
//
// # Ethreum builtin
//
// ecrecover: 0x0000000000000000000000000000000000000001
// sha256:    0x0000000000000000000000000000000000000002
// ripemd160: 0x0000000000000000000000000000000000000003
// identity:  0x0000000000000000000000000000000000000004
//
// # CITA builtin
//
// edrecover: 0x0000000000000000000000000000000000ff0001
//
// # All
//
//     Start: 0xffffffffffffffffffffffffffffffffff000000
//     End  : 0xffffffffffffffffffffffffffffffffffffffff
//
// ## Action Address:
//
//     Start: 0xffffffffffffffffffffffffffffffffff010000
//     End  : 0xffffffffffffffffffffffffffffffffff01ffff
//
// ### Normal Action Address
//
//     Start: 0xffffffffffffffffffffffffffffffffff010000
//     End  : 0xffffffffffffffffffffffffffffffffff0100ff
//
// ### Go Action Address
//
//     Start: 0xffffffffffffffffffffffffffffffffff018000
//     End  : 0xffffffffffffffffffffffffffffffffff018fff
//
// ## System Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff020000
//     End  : 0xffffffffffffffffffffffffffffffffff02ffff
//
// ### Normal System Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff020000
//     End  : 0xffffffffffffffffffffffffffffffffff0200ff
//
// ### Permission System Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff021000
//     End  : 0xffffffffffffffffffffffffffffffffff0210ff
//
// ## Native Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff030000
//     End  : 0xffffffffffffffffffffffffffffffffff03ffff
//

// Ethereum builtin address
pub const ECRECOVER_ADDRESS: &str = "0000000000000000000000000000000000000001";
pub const SHA256_ADDRESS: &str = "0000000000000000000000000000000000000002";
pub const RIPEMD160_ADDRESS: &str = "0000000000000000000000000000000000000003";
pub const IDENTITY_ADDRESS: &str = "0000000000000000000000000000000000000004";

// CITA builtin address
pub const EDRECOVER_ADDRESS: &str = "0000000000000000000000000000000000ff0001";

// Normal Action Address
pub const STORE_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010000";
pub const ABI_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010001";
pub const AMEND_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010002";
// Go Action Address
pub const GO_CONTRACT: &str = "ffffffffffffffffffffffffffffffffff018000";
pub const GO_CONTRACT_MIN: &str = "ffffffffffffffffffffffffffffffffff018001";
pub const GO_CONTRACT_MAX: &str = "ffffffffffffffffffffffffffffffffff018fff";
// Normal System Contracts
pub const SYS_CONFIG: &str = "ffffffffffffffffffffffffffffffffff020000";
pub const NODE_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020001";
pub const CHAIN_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020002";
pub const QUOTA_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020003";
pub const PERMISSION_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020004";
pub const PERMISSION_CREATOR: &str = "ffffffffffffffffffffffffffffffffff020005";
pub const AUTHORIZATION: &str = "ffffffffffffffffffffffffffffffffff020006";
pub const ROLE_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020007";
pub const ROLE_CREATOR: &str = "ffffffffffffffffffffffffffffffffff020008";
pub const GROUP: &str = "ffffffffffffffffffffffffffffffffff020009";
pub const GROUP_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff02000a";
pub const GROUP_CREATOR: &str = "ffffffffffffffffffffffffffffffffff02000b";
pub const ADMIN: &str = "ffffffffffffffffffffffffffffffffff02000c";
pub const ROLE_AUTH: &str = "ffffffffffffffffffffffffffffffffff02000d";
pub const BATCH_TX: &str = "ffffffffffffffffffffffffffffffffff02000e";
pub const EMERGENCY_BRAKE: &str = "ffffffffffffffffffffffffffffffffff02000f";
pub const PRICE_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020010";
pub const VERSION_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020011";
// Permission System Contracts
pub const PERMISSION_SEND_TX: &str = "ffffffffffffffffffffffffffffffffff021000";
pub const PERMISSION_CREATE_CONTRACT: &str = "ffffffffffffffffffffffffffffffffff021001";
pub const PERMISSION_NEW_PERMISSION: &str = "ffffffffffffffffffffffffffffffffff021010";
pub const PERMISSION_DELETE_PERMISSION: &str = "ffffffffffffffffffffffffffffffffff021011";
pub const PERMISSION_UPDATE_PERMISSION: &str = "ffffffffffffffffffffffffffffffffff021012";
pub const PERMISSION_SET_AUTH: &str = "ffffffffffffffffffffffffffffffffff021013";
pub const PERMISSION_CANCEL_AUTH: &str = "ffffffffffffffffffffffffffffffffff021014";
pub const PERMISSION_NEW_ROLE: &str = "ffffffffffffffffffffffffffffffffff021015";
pub const PERMISSION_DELETE_ROLE: &str = "ffffffffffffffffffffffffffffffffff021016";
pub const PERMISSION_UPDATE_ROLE: &str = "ffffffffffffffffffffffffffffffffff021017";
pub const PERMISSION_SET_ROLE: &str = "ffffffffffffffffffffffffffffffffff021018";
pub const PERMISSION_CANCEL_ROLE: &str = "ffffffffffffffffffffffffffffffffff021019";
pub const PERMISSION_NEW_GROUP: &str = "ffffffffffffffffffffffffffffffffff02101a";
pub const PERMISSION_DELETE_GROUP: &str = "ffffffffffffffffffffffffffffffffff02101b";
pub const PERMISSION_UPDATE_GROUP: &str = "ffffffffffffffffffffffffffffffffff02101c";
pub const PERMISSION_NEW_NODE: &str = "ffffffffffffffffffffffffffffffffff021020";
pub const PERMISSION_DELETE_NODE: &str = "ffffffffffffffffffffffffffffffffff021021";
pub const PERMISSION_UPDATE_NODE: &str = "ffffffffffffffffffffffffffffffffff021022";
pub const PERMISSION_ACCOUNT_QUOTA: &str = "ffffffffffffffffffffffffffffffffff021023";
pub const PERMISSION_BLOCK_QUOTA: &str = "ffffffffffffffffffffffffffffffffff021024";
pub const PERMISSION_BATCH_TX: &str = "ffffffffffffffffffffffffffffffffff021025";
pub const PERMISSION_EMERGENCY_BRAKE: &str = "ffffffffffffffffffffffffffffffffff021026";
pub const PERMISSION_QUOTA_PRICE: &str = "ffffffffffffffffffffffffffffffffff021027";
pub const PERMISSION_VERSION: &str = "ffffffffffffffffffffffffffffffffff021028";

// Native Contracts
pub const NATIVE_SIMPLE_STORAGE: &str = "ffffffffffffffffffffffffffffffffff030000";
pub const NATIVE_ZK_PRIVACY: &str = "ffffffffffffffffffffffffffffffffff030001";
pub const NATIVE_CROSS_CHAIN_VERIFY: &str = "ffffffffffffffffffffffffffffffffff030002";
<commit_msg>Add missed reserced address.<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Define all Reserved Addresses.
// # Builtin
//
// # Ethreum builtin
//
// ecrecover: 0x0000000000000000000000000000000000000001
// sha256:    0x0000000000000000000000000000000000000002
// ripemd160: 0x0000000000000000000000000000000000000003
// identity:  0x0000000000000000000000000000000000000004
//
// # CITA builtin
//
// edrecover: 0x0000000000000000000000000000000000ff0001
//
// # All
//
//     Start: 0xffffffffffffffffffffffffffffffffff000000
//     End  : 0xffffffffffffffffffffffffffffffffffffffff
//
// ## Action Address:
//
//     Start: 0xffffffffffffffffffffffffffffffffff010000
//     End  : 0xffffffffffffffffffffffffffffffffff01ffff
//
// ### Normal Action Address
//
//     Start: 0xffffffffffffffffffffffffffffffffff010000
//     End  : 0xffffffffffffffffffffffffffffffffff0100ff
//
// ### Go Action Address
//
//     Start: 0xffffffffffffffffffffffffffffffffff018000
//     End  : 0xffffffffffffffffffffffffffffffffff018fff
//
// ## System Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff020000
//     End  : 0xffffffffffffffffffffffffffffffffff02ffff
//
// ### Normal System Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff020000
//     End  : 0xffffffffffffffffffffffffffffffffff0200ff
//
// ### Permission System Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff021000
//     End  : 0xffffffffffffffffffffffffffffffffff0210ff
//
// ## Native Contracts
//
//     Start: 0xffffffffffffffffffffffffffffffffff030000
//     End  : 0xffffffffffffffffffffffffffffffffff03ffff
//

// Ethereum builtin address
pub const ECRECOVER_ADDRESS: &str = "0000000000000000000000000000000000000001";
pub const SHA256_ADDRESS: &str = "0000000000000000000000000000000000000002";
pub const RIPEMD160_ADDRESS: &str = "0000000000000000000000000000000000000003";
pub const IDENTITY_ADDRESS: &str = "0000000000000000000000000000000000000004";

// CITA builtin address
pub const EDRECOVER_ADDRESS: &str = "0000000000000000000000000000000000ff0001";

// Normal Action Address
pub const STORE_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010000";
pub const ABI_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010001";
pub const AMEND_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010002";
// Go Action Address
pub const GO_CONTRACT: &str = "ffffffffffffffffffffffffffffffffff018000";
pub const GO_CONTRACT_MIN: &str = "ffffffffffffffffffffffffffffffffff018001";
pub const GO_CONTRACT_MAX: &str = "ffffffffffffffffffffffffffffffffff018fff";
// Normal System Contracts
pub const SYS_CONFIG: &str = "ffffffffffffffffffffffffffffffffff020000";
pub const NODE_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020001";
pub const CHAIN_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020002";
pub const QUOTA_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020003";
pub const PERMISSION_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020004";
pub const PERMISSION_CREATOR: &str = "ffffffffffffffffffffffffffffffffff020005";
pub const AUTHORIZATION: &str = "ffffffffffffffffffffffffffffffffff020006";
pub const ROLE_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020007";
pub const ROLE_CREATOR: &str = "ffffffffffffffffffffffffffffffffff020008";
pub const GROUP: &str = "ffffffffffffffffffffffffffffffffff020009";
pub const GROUP_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff02000a";
pub const GROUP_CREATOR: &str = "ffffffffffffffffffffffffffffffffff02000b";
pub const ADMIN: &str = "ffffffffffffffffffffffffffffffffff02000c";
pub const ROLE_AUTH: &str = "ffffffffffffffffffffffffffffffffff02000d";
pub const BATCH_TX: &str = "ffffffffffffffffffffffffffffffffff02000e";
pub const EMERGENCY_BRAKE: &str = "ffffffffffffffffffffffffffffffffff02000f";
pub const PRICE_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020010";
pub const VERSION_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020011";
pub const ALL_GROUPS: &str = "ffffffffffffffffffffffffffffffffff020012";
// Permission System Contracts
pub const PERMISSION_SEND_TX: &str = "ffffffffffffffffffffffffffffffffff021000";
pub const PERMISSION_CREATE_CONTRACT: &str = "ffffffffffffffffffffffffffffffffff021001";
pub const PERMISSION_NEW_PERMISSION: &str = "ffffffffffffffffffffffffffffffffff021010";
pub const PERMISSION_DELETE_PERMISSION: &str = "ffffffffffffffffffffffffffffffffff021011";
pub const PERMISSION_UPDATE_PERMISSION: &str = "ffffffffffffffffffffffffffffffffff021012";
pub const PERMISSION_SET_AUTH: &str = "ffffffffffffffffffffffffffffffffff021013";
pub const PERMISSION_CANCEL_AUTH: &str = "ffffffffffffffffffffffffffffffffff021014";
pub const PERMISSION_NEW_ROLE: &str = "ffffffffffffffffffffffffffffffffff021015";
pub const PERMISSION_DELETE_ROLE: &str = "ffffffffffffffffffffffffffffffffff021016";
pub const PERMISSION_UPDATE_ROLE: &str = "ffffffffffffffffffffffffffffffffff021017";
pub const PERMISSION_SET_ROLE: &str = "ffffffffffffffffffffffffffffffffff021018";
pub const PERMISSION_CANCEL_ROLE: &str = "ffffffffffffffffffffffffffffffffff021019";
pub const PERMISSION_NEW_GROUP: &str = "ffffffffffffffffffffffffffffffffff02101a";
pub const PERMISSION_DELETE_GROUP: &str = "ffffffffffffffffffffffffffffffffff02101b";
pub const PERMISSION_UPDATE_GROUP: &str = "ffffffffffffffffffffffffffffffffff02101c";
pub const PERMISSION_NEW_NODE: &str = "ffffffffffffffffffffffffffffffffff021020";
pub const PERMISSION_DELETE_NODE: &str = "ffffffffffffffffffffffffffffffffff021021";
pub const PERMISSION_UPDATE_NODE: &str = "ffffffffffffffffffffffffffffffffff021022";
pub const PERMISSION_ACCOUNT_QUOTA: &str = "ffffffffffffffffffffffffffffffffff021023";
pub const PERMISSION_BLOCK_QUOTA: &str = "ffffffffffffffffffffffffffffffffff021024";
pub const PERMISSION_BATCH_TX: &str = "ffffffffffffffffffffffffffffffffff021025";
pub const PERMISSION_EMERGENCY_BRAKE: &str = "ffffffffffffffffffffffffffffffffff021026";
pub const PERMISSION_QUOTA_PRICE: &str = "ffffffffffffffffffffffffffffffffff021027";
pub const PERMISSION_VERSION: &str = "ffffffffffffffffffffffffffffffffff021028";

// Native Contracts
pub const NATIVE_SIMPLE_STORAGE: &str = "ffffffffffffffffffffffffffffffffff030000";
pub const NATIVE_ZK_PRIVACY: &str = "ffffffffffffffffffffffffffffffffff030001";
pub const NATIVE_CROSS_CHAIN_VERIFY: &str = "ffffffffffffffffffffffffffffffffff030002";
<|endoftext|>


<commit_before>//! All routes related to managing owners of a crate

use crate::controllers::prelude::*;
use crate::models::{Crate, Owner, Rights, Team, User};
use crate::views::EncodableOwner;

/// Handles the `GET /crates/:crate_id/owners` route.
pub fn owners(req: &mut dyn RequestExt) -> EndpointResult {
    let crate_name = &req.params()["crate_id"];
    let conn = req.db_read_only()?;
    let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
    let owners = krate.owners(&conn)?.into_iter().map(Owner::into).collect();

    #[derive(Serialize)]
    struct R {
        users: Vec<EncodableOwner>,
    }
    Ok(req.json(&R { users: owners }))
}

/// Handles the `GET /crates/:crate_id/owner_team` route.
pub fn owner_team(req: &mut dyn RequestExt) -> EndpointResult {
    let crate_name = &req.params()["crate_id"];
    let conn = req.db_read_only()?;
    let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
    let owners = Team::owning(&krate, &conn)?
        .into_iter()
        .map(Owner::into)
        .collect();

    #[derive(Serialize)]
    struct R {
        teams: Vec<EncodableOwner>,
    }
    Ok(req.json(&R { teams: owners }))
}

/// Handles the `GET /crates/:crate_id/owner_user` route.
pub fn owner_user(req: &mut dyn RequestExt) -> EndpointResult {
    let crate_name = &req.params()["crate_id"];
    let conn = req.db_read_only()?;
    let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
    let owners = User::owning(&krate, &conn)?
        .into_iter()
        .map(Owner::into)
        .collect();

    #[derive(Serialize)]
    struct R {
        users: Vec<EncodableOwner>,
    }
    Ok(req.json(&R { users: owners }))
}

/// Handles the `PUT /crates/:crate_id/owners` route.
pub fn add_owners(req: &mut dyn RequestExt) -> EndpointResult {
    modify_owners(req, true)
}

/// Handles the `DELETE /crates/:crate_id/owners` route.
pub fn remove_owners(req: &mut dyn RequestExt) -> EndpointResult {
    modify_owners(req, false)
}

/// Parse the JSON request body of requests to modify the owners of a crate.
/// The format is
///
///     {"owners": ["username", "github:org:team", ...]}
fn parse_owners_request(req: &mut dyn RequestExt) -> AppResult<Vec<String>> {
    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    #[derive(Deserialize)]
    struct Request {
        // identical, for back-compat (owners preferred)
        users: Option<Vec<String>>,
        owners: Option<Vec<String>>,
    }
    let request: Request =
        serde_json::from_str(&body).map_err(|_| cargo_err("invalid json request"))?;
    request
        .owners
        .or(request.users)
        .ok_or_else(|| cargo_err("invalid json request"))
}

fn modify_owners(req: &mut dyn RequestExt, add: bool) -> EndpointResult {
    let authenticated_user = req.authenticate()?;
    let logins = parse_owners_request(req)?;
    let app = req.app();
    let crate_name = &req.params()["crate_id"];

    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    conn.transaction(|| {
        let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
        let owners = krate.owners(&conn)?;

        match user.rights(app, &owners)? {
            Rights::Full => {}
            // Yes!
            Rights::Publish => {
                return Err(cargo_err(
                    "team members don't have permission to modify owners",
                ));
            }
            Rights::None => {
                return Err(cargo_err("only owners have permission to modify owners"));
            }
        }

        let comma_sep_msg = if add {
            let mut msgs = Vec::with_capacity(logins.len());
            for login in &logins {
                let login_test =
                    |owner: &Owner| owner.login().to_lowercase() == *login.to_lowercase();
                if owners.iter().any(login_test) {
                    return Err(cargo_err(&format_args!("`{}` is already an owner", login)));
                }
                let msg = krate.owner_add(app, &conn, &user, login)?;
                msgs.push(msg);
            }
            msgs.join(",")
        } else {
            for login in &logins {
                krate.owner_remove(app, &conn, &user, login)?;
            }
            if User::owning(&krate, &conn)?.is_empty() {
                return Err(cargo_err(
                    "cannot remove all individual owners of a crate. \
                     Team member don't have permission to modify owners, so \
                     at least one individual owner is required.",
                ));
            }
            "owners successfully removed".to_owned()
        };

        #[derive(Serialize)]
        struct R {
            ok: bool,
            msg: String,
        }
        Ok(req.json(&R {
            ok: true,
            msg: comma_sep_msg,
        }))
    })
}
<commit_msg>controllers::krate::owners: Use `json!` macro to simplify JSON serialization code<commit_after>//! All routes related to managing owners of a crate

use crate::controllers::prelude::*;
use crate::models::{Crate, Owner, Rights, Team, User};
use crate::views::EncodableOwner;

/// Handles the `GET /crates/:crate_id/owners` route.
pub fn owners(req: &mut dyn RequestExt) -> EndpointResult {
    let crate_name = &req.params()["crate_id"];
    let conn = req.db_read_only()?;
    let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
    let owners = krate
        .owners(&conn)?
        .into_iter()
        .map(Owner::into)
        .collect::<Vec<EncodableOwner>>();

    Ok(req.json(&json!({ "users": owners })))
}

/// Handles the `GET /crates/:crate_id/owner_team` route.
pub fn owner_team(req: &mut dyn RequestExt) -> EndpointResult {
    let crate_name = &req.params()["crate_id"];
    let conn = req.db_read_only()?;
    let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
    let owners = Team::owning(&krate, &conn)?
        .into_iter()
        .map(Owner::into)
        .collect::<Vec<EncodableOwner>>();

    Ok(req.json(&json!({ "teams": owners })))
}

/// Handles the `GET /crates/:crate_id/owner_user` route.
pub fn owner_user(req: &mut dyn RequestExt) -> EndpointResult {
    let crate_name = &req.params()["crate_id"];
    let conn = req.db_read_only()?;
    let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
    let owners = User::owning(&krate, &conn)?
        .into_iter()
        .map(Owner::into)
        .collect::<Vec<EncodableOwner>>();

    Ok(req.json(&json!({ "users": owners })))
}

/// Handles the `PUT /crates/:crate_id/owners` route.
pub fn add_owners(req: &mut dyn RequestExt) -> EndpointResult {
    modify_owners(req, true)
}

/// Handles the `DELETE /crates/:crate_id/owners` route.
pub fn remove_owners(req: &mut dyn RequestExt) -> EndpointResult {
    modify_owners(req, false)
}

/// Parse the JSON request body of requests to modify the owners of a crate.
/// The format is
///
///     {"owners": ["username", "github:org:team", ...]}
fn parse_owners_request(req: &mut dyn RequestExt) -> AppResult<Vec<String>> {
    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    #[derive(Deserialize)]
    struct Request {
        // identical, for back-compat (owners preferred)
        users: Option<Vec<String>>,
        owners: Option<Vec<String>>,
    }
    let request: Request =
        serde_json::from_str(&body).map_err(|_| cargo_err("invalid json request"))?;
    request
        .owners
        .or(request.users)
        .ok_or_else(|| cargo_err("invalid json request"))
}

fn modify_owners(req: &mut dyn RequestExt, add: bool) -> EndpointResult {
    let authenticated_user = req.authenticate()?;
    let logins = parse_owners_request(req)?;
    let app = req.app();
    let crate_name = &req.params()["crate_id"];

    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    conn.transaction(|| {
        let krate: Crate = Crate::by_name(crate_name).first(&*conn)?;
        let owners = krate.owners(&conn)?;

        match user.rights(app, &owners)? {
            Rights::Full => {}
            // Yes!
            Rights::Publish => {
                return Err(cargo_err(
                    "team members don't have permission to modify owners",
                ));
            }
            Rights::None => {
                return Err(cargo_err("only owners have permission to modify owners"));
            }
        }

        let comma_sep_msg = if add {
            let mut msgs = Vec::with_capacity(logins.len());
            for login in &logins {
                let login_test =
                    |owner: &Owner| owner.login().to_lowercase() == *login.to_lowercase();
                if owners.iter().any(login_test) {
                    return Err(cargo_err(&format_args!("`{}` is already an owner", login)));
                }
                let msg = krate.owner_add(app, &conn, &user, login)?;
                msgs.push(msg);
            }
            msgs.join(",")
        } else {
            for login in &logins {
                krate.owner_remove(app, &conn, &user, login)?;
            }
            if User::owning(&krate, &conn)?.is_empty() {
                return Err(cargo_err(
                    "cannot remove all individual owners of a crate. \
                     Team member don't have permission to modify owners, so \
                     at least one individual owner is required.",
                ));
            }
            "owners successfully removed".to_owned()
        };

        Ok(req.json(&json!({ "ok": true, "msg": comma_sep_msg })))
    })
}
<|endoftext|>


<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/. */

//! Gecko-specific bits for selector-parsing.

use cssparser::ToCss;
use element_state::ElementState;
use gecko_bindings::structs::CSSPseudoClassType;
use selector_parser::{SelectorParser, PseudoElementCascadeType};
use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
use selectors::parser::AttrSelector;
use std::borrow::Cow;
use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};

/// A representation of a CSS pseudo-element.
///
/// In Gecko, we represent pseudo-elements as plain `Atom`s.
///
/// The boolean field represents whether this element is an anonymous box. This
/// is just for convenience, instead of recomputing it.
///
/// Also, note that the `Atom` member is always a static atom, so if space is a
/// concern, we can use the raw pointer and use the lower bit to represent it
/// without space overhead.
///
/// FIXME(emilio): we know all these atoms are static. Patches are starting to
/// pile up, but a further potential optimisation is generating bindings without
/// `-no-gen-bitfield-methods` (that was removed to compile on stable, but it no
/// longer depends on it), and using the raw *mut nsIAtom (properly asserting
/// we're a static atom).
///
/// This should allow us to avoid random FFI overhead when cloning/dropping
/// pseudos.
///
/// Also, we can further optimize PartialEq and hash comparing/hashing only the
/// atoms.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PseudoElement(Atom, bool);

impl PseudoElement {
    /// Get the pseudo-element as an atom.
    #[inline]
    pub fn as_atom(&self) -> &Atom {
        &self.0
    }

    /// Whether this pseudo-element is an anonymous box.
    #[inline]
    fn is_anon_box(&self) -> bool {
        self.1
    }

    /// Construct a pseudo-element from an `Atom`, receiving whether it is also
    /// an anonymous box, and don't check it on release builds.
    ///
    /// On debug builds we assert it's the result we expect.
    #[inline]
    pub fn from_atom_unchecked(atom: Atom, is_anon_box: bool) -> Self {
        if cfg!(debug_assertions) {
            // Do the check on debug regardless.
            match Self::from_atom(&*atom, true) {
                Some(pseudo) => {
                    assert_eq!(pseudo.is_anon_box(), is_anon_box);
                    return pseudo;
                }
                None => panic!("Unknown pseudo: {:?}", atom),
            }
        }

        PseudoElement(atom, is_anon_box)
    }

    #[inline]
    fn from_atom(atom: &WeakAtom, _in_ua: bool) -> Option<Self> {
        macro_rules! pseudo_element {
            ($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
                if atom == &*$atom {
                    return Some(PseudoElement($atom, $is_anon_box));
                }
            }}
        }

        include!("generated/gecko_pseudo_element_helper.rs");

        None
    }

    /// Constructs an atom from a string of text, and whether we're in a
    /// user-agent stylesheet.
    ///
    /// If we're not in a user-agent stylesheet, we will never parse anonymous
    /// box pseudo-elements.
    ///
    /// Returns `None` if the pseudo-element is not recognised.
    #[inline]
    fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
        use std::ascii::AsciiExt;
        macro_rules! pseudo_element {
            ($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
                if !$is_anon_box || in_ua_stylesheet {
                    if s.eq_ignore_ascii_case(&$pseudo_str_with_colon[1..]) {
                        return Some(PseudoElement($atom, $is_anon_box))
                    }
                }
            }}
        }

        include!("generated/gecko_pseudo_element_helper.rs");

        None
    }
}

impl ToCss for PseudoElement {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        // FIXME: why does the atom contain one colon? Pseudo-element has two
        debug_assert!(self.0.as_slice().starts_with(&[b':' as u16]) &&
                      !self.0.as_slice().starts_with(&[b':' as u16, b':' as u16]));
        try!(dest.write_char(':'));
        write!(dest, "{}", self.0)
    }
}

/// Our representation of a non tree-structural pseudo-class.
///
/// FIXME(emilio): Find a way to autogenerate this.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum NonTSPseudoClass {
    /// :any-link
    AnyLink,
    /// :link
    Link,
    /// :visited
    Visited,
    /// :active
    Active,
    /// :focus
    Focus,
    /// :fullscreen
    Fullscreen,
    /// :hover
    Hover,
    /// :enabled
    Enabled,
    /// :disabled
    Disabled,
    /// :checked
    Checked,
    /// :indeterminate
    Indeterminate,
    /// :read-write
    ReadWrite,
    /// :read-only
    ReadOnly,
}

impl ToCss for NonTSPseudoClass {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        use self::NonTSPseudoClass::*;
        dest.write_str(match *self {
            AnyLink => ":any-link",
            Link => ":link",
            Visited => ":visited",
            Active => ":active",
            Focus => ":focus",
            Fullscreen => ":fullscreen",
            Hover => ":hover",
            Enabled => ":enabled",
            Disabled => ":disabled",
            Checked => ":checked",
            Indeterminate => ":indeterminate",
            ReadWrite => ":read-write",
            ReadOnly => ":read-only",
        })
    }
}

impl NonTSPseudoClass {
    /// Get the state flag associated with a pseudo-class, if any.
    pub fn state_flag(&self) -> ElementState {
        use element_state::*;
        use self::NonTSPseudoClass::*;
        match *self {
            Active => IN_ACTIVE_STATE,
            Focus => IN_FOCUS_STATE,
            Fullscreen => IN_FULLSCREEN_STATE,
            Hover => IN_HOVER_STATE,
            Enabled => IN_ENABLED_STATE,
            Disabled => IN_DISABLED_STATE,
            Checked => IN_CHECKED_STATE,
            Indeterminate => IN_INDETERMINATE_STATE,
            ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

            AnyLink |
            Link |
            Visited => ElementState::empty(),
        }
    }

    /// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType.
    pub fn to_gecko_pseudoclasstype(&self) -> Option<CSSPseudoClassType> {
        use gecko_bindings::structs::CSSPseudoClassType::*;
        use self::NonTSPseudoClass::*;
        Some(match *self {
            AnyLink => anyLink,
            Link => link,
            Visited => visited,
            Active => active,
            Focus => focus,
            Fullscreen => fullscreen,
            Hover => hover,
            Enabled => enabled,
            Disabled => disabled,
            Checked => checked,
            Indeterminate => indeterminate,
            ReadWrite | ReadOnly => { return None; }
        })
    }
}

/// The dummy struct we use to implement our selector parsing.
#[derive(Clone, Debug, PartialEq)]
pub struct SelectorImpl;

impl ::selectors::SelectorImpl for SelectorImpl {
    type AttrValue = Atom;
    type Identifier = Atom;
    type ClassName = Atom;
    type LocalName = Atom;
    type NamespacePrefix = Atom;
    type NamespaceUrl = Namespace;
    type BorrowedNamespaceUrl = WeakNamespace;
    type BorrowedLocalName = WeakAtom;

    type PseudoElement = PseudoElement;
    type NonTSPseudoClass = NonTSPseudoClass;

    fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
        attr_exists_selector_is_shareable(attr_selector)
    }

    fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
                                         value: &Self::AttrValue) -> bool {
        attr_equals_selector_is_shareable(attr_selector, value)
    }
}

impl<'a> ::selectors::Parser for SelectorParser<'a> {
    type Impl = SelectorImpl;

    fn parse_non_ts_pseudo_class(&self, name: Cow<str>) -> Result<NonTSPseudoClass, ()> {
        use self::NonTSPseudoClass::*;
        let pseudo_class = match_ignore_ascii_case! { &name,
            "any-link" => AnyLink,
            "link" => Link,
            "visited" => Visited,
            "active" => Active,
            "focus" => Focus,
            "fullscreen" => Fullscreen,
            "hover" => Hover,
            "enabled" => Enabled,
            "disabled" => Disabled,
            "checked" => Checked,
            "indeterminate" => Indeterminate,
            "read-write" => ReadWrite,
            "read-only" => ReadOnly,
            _ => return Err(())
        };

        Ok(pseudo_class)
    }

    fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
        match PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) {
            Some(pseudo) => Ok(pseudo),
            None => Err(()),
        }
    }

    fn default_namespace(&self) -> Option<Namespace> {
        self.namespaces.default.clone()
    }

    fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> {
        self.namespaces.prefixes.get(prefix).cloned()
    }
}

impl SelectorImpl {
    #[inline]
    /// Returns the kind of cascade type that a given pseudo is going to use.
    ///
    /// In Gecko we only compute ::before and ::after eagerly. We save the rules
    /// for anonymous boxes separately, so we resolve them as precomputed
    /// pseudos.
    ///
    /// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
    pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
        if Self::pseudo_is_before_or_after(pseudo) {
            return PseudoElementCascadeType::Eager
        }

        if pseudo.is_anon_box() {
            return PseudoElementCascadeType::Precomputed
        }

        PseudoElementCascadeType::Lazy
    }

    #[inline]
    /// Executes a function for each pseudo-element.
    pub fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(PseudoElement),
    {
        macro_rules! pseudo_element {
            ($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
                fun(PseudoElement($atom, $is_anon_box));
            }}
        }

        include!("generated/gecko_pseudo_element_helper.rs")
    }

    #[inline]
    /// Returns whether the given pseudo-element is `::before` or `::after`.
    pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
        *pseudo.as_atom() == atom!(":before") ||
        *pseudo.as_atom() == atom!(":after")
    }

    #[inline]
    /// Returns the relevant state flag for a given non-tree-structural
    /// pseudo-class.
    pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
        pc.state_flag()
    }
}
<commit_msg>Add NonTSPseudoClass::is_internal function<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/. */

//! Gecko-specific bits for selector-parsing.

use cssparser::ToCss;
use element_state::ElementState;
use gecko_bindings::structs::CSSPseudoClassType;
use selector_parser::{SelectorParser, PseudoElementCascadeType};
use selector_parser::{attr_equals_selector_is_shareable, attr_exists_selector_is_shareable};
use selectors::parser::AttrSelector;
use std::borrow::Cow;
use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};

/// A representation of a CSS pseudo-element.
///
/// In Gecko, we represent pseudo-elements as plain `Atom`s.
///
/// The boolean field represents whether this element is an anonymous box. This
/// is just for convenience, instead of recomputing it.
///
/// Also, note that the `Atom` member is always a static atom, so if space is a
/// concern, we can use the raw pointer and use the lower bit to represent it
/// without space overhead.
///
/// FIXME(emilio): we know all these atoms are static. Patches are starting to
/// pile up, but a further potential optimisation is generating bindings without
/// `-no-gen-bitfield-methods` (that was removed to compile on stable, but it no
/// longer depends on it), and using the raw *mut nsIAtom (properly asserting
/// we're a static atom).
///
/// This should allow us to avoid random FFI overhead when cloning/dropping
/// pseudos.
///
/// Also, we can further optimize PartialEq and hash comparing/hashing only the
/// atoms.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PseudoElement(Atom, bool);

impl PseudoElement {
    /// Get the pseudo-element as an atom.
    #[inline]
    pub fn as_atom(&self) -> &Atom {
        &self.0
    }

    /// Whether this pseudo-element is an anonymous box.
    #[inline]
    fn is_anon_box(&self) -> bool {
        self.1
    }

    /// Construct a pseudo-element from an `Atom`, receiving whether it is also
    /// an anonymous box, and don't check it on release builds.
    ///
    /// On debug builds we assert it's the result we expect.
    #[inline]
    pub fn from_atom_unchecked(atom: Atom, is_anon_box: bool) -> Self {
        if cfg!(debug_assertions) {
            // Do the check on debug regardless.
            match Self::from_atom(&*atom, true) {
                Some(pseudo) => {
                    assert_eq!(pseudo.is_anon_box(), is_anon_box);
                    return pseudo;
                }
                None => panic!("Unknown pseudo: {:?}", atom),
            }
        }

        PseudoElement(atom, is_anon_box)
    }

    #[inline]
    fn from_atom(atom: &WeakAtom, _in_ua: bool) -> Option<Self> {
        macro_rules! pseudo_element {
            ($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
                if atom == &*$atom {
                    return Some(PseudoElement($atom, $is_anon_box));
                }
            }}
        }

        include!("generated/gecko_pseudo_element_helper.rs");

        None
    }

    /// Constructs an atom from a string of text, and whether we're in a
    /// user-agent stylesheet.
    ///
    /// If we're not in a user-agent stylesheet, we will never parse anonymous
    /// box pseudo-elements.
    ///
    /// Returns `None` if the pseudo-element is not recognised.
    #[inline]
    fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
        use std::ascii::AsciiExt;
        macro_rules! pseudo_element {
            ($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
                if !$is_anon_box || in_ua_stylesheet {
                    if s.eq_ignore_ascii_case(&$pseudo_str_with_colon[1..]) {
                        return Some(PseudoElement($atom, $is_anon_box))
                    }
                }
            }}
        }

        include!("generated/gecko_pseudo_element_helper.rs");

        None
    }
}

impl ToCss for PseudoElement {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        // FIXME: why does the atom contain one colon? Pseudo-element has two
        debug_assert!(self.0.as_slice().starts_with(&[b':' as u16]) &&
                      !self.0.as_slice().starts_with(&[b':' as u16, b':' as u16]));
        try!(dest.write_char(':'));
        write!(dest, "{}", self.0)
    }
}

/// Our representation of a non tree-structural pseudo-class.
///
/// FIXME(emilio): Find a way to autogenerate this.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum NonTSPseudoClass {
    /// :any-link
    AnyLink,
    /// :link
    Link,
    /// :visited
    Visited,
    /// :active
    Active,
    /// :focus
    Focus,
    /// :fullscreen
    Fullscreen,
    /// :hover
    Hover,
    /// :enabled
    Enabled,
    /// :disabled
    Disabled,
    /// :checked
    Checked,
    /// :indeterminate
    Indeterminate,
    /// :read-write
    ReadWrite,
    /// :read-only
    ReadOnly,
}

impl ToCss for NonTSPseudoClass {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        use self::NonTSPseudoClass::*;
        dest.write_str(match *self {
            AnyLink => ":any-link",
            Link => ":link",
            Visited => ":visited",
            Active => ":active",
            Focus => ":focus",
            Fullscreen => ":fullscreen",
            Hover => ":hover",
            Enabled => ":enabled",
            Disabled => ":disabled",
            Checked => ":checked",
            Indeterminate => ":indeterminate",
            ReadWrite => ":read-write",
            ReadOnly => ":read-only",
        })
    }
}

impl NonTSPseudoClass {
    /// A pseudo-class is internal if it can only be used inside
    /// user agent style sheets.
    pub fn is_internal(&self) -> bool {
        use self::NonTSPseudoClass::*;
        match *self {
            AnyLink |
            Link |
            Visited |
            Active |
            Focus |
            Fullscreen |
            Hover |
            Enabled |
            Disabled |
            Checked |
            Indeterminate |
            ReadWrite |
            ReadOnly => false,
        }
    }

    /// Get the state flag associated with a pseudo-class, if any.
    pub fn state_flag(&self) -> ElementState {
        use element_state::*;
        use self::NonTSPseudoClass::*;
        match *self {
            Active => IN_ACTIVE_STATE,
            Focus => IN_FOCUS_STATE,
            Fullscreen => IN_FULLSCREEN_STATE,
            Hover => IN_HOVER_STATE,
            Enabled => IN_ENABLED_STATE,
            Disabled => IN_DISABLED_STATE,
            Checked => IN_CHECKED_STATE,
            Indeterminate => IN_INDETERMINATE_STATE,
            ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

            AnyLink |
            Link |
            Visited => ElementState::empty(),
        }
    }

    /// Convert NonTSPseudoClass to Gecko's CSSPseudoClassType.
    pub fn to_gecko_pseudoclasstype(&self) -> Option<CSSPseudoClassType> {
        use gecko_bindings::structs::CSSPseudoClassType::*;
        use self::NonTSPseudoClass::*;
        Some(match *self {
            AnyLink => anyLink,
            Link => link,
            Visited => visited,
            Active => active,
            Focus => focus,
            Fullscreen => fullscreen,
            Hover => hover,
            Enabled => enabled,
            Disabled => disabled,
            Checked => checked,
            Indeterminate => indeterminate,
            ReadWrite | ReadOnly => { return None; }
        })
    }
}

/// The dummy struct we use to implement our selector parsing.
#[derive(Clone, Debug, PartialEq)]
pub struct SelectorImpl;

impl ::selectors::SelectorImpl for SelectorImpl {
    type AttrValue = Atom;
    type Identifier = Atom;
    type ClassName = Atom;
    type LocalName = Atom;
    type NamespacePrefix = Atom;
    type NamespaceUrl = Namespace;
    type BorrowedNamespaceUrl = WeakNamespace;
    type BorrowedLocalName = WeakAtom;

    type PseudoElement = PseudoElement;
    type NonTSPseudoClass = NonTSPseudoClass;

    fn attr_exists_selector_is_shareable(attr_selector: &AttrSelector<Self>) -> bool {
        attr_exists_selector_is_shareable(attr_selector)
    }

    fn attr_equals_selector_is_shareable(attr_selector: &AttrSelector<Self>,
                                         value: &Self::AttrValue) -> bool {
        attr_equals_selector_is_shareable(attr_selector, value)
    }
}

impl<'a> ::selectors::Parser for SelectorParser<'a> {
    type Impl = SelectorImpl;

    fn parse_non_ts_pseudo_class(&self, name: Cow<str>) -> Result<NonTSPseudoClass, ()> {
        use self::NonTSPseudoClass::*;
        let pseudo_class = match_ignore_ascii_case! { &name,
            "any-link" => AnyLink,
            "link" => Link,
            "visited" => Visited,
            "active" => Active,
            "focus" => Focus,
            "fullscreen" => Fullscreen,
            "hover" => Hover,
            "enabled" => Enabled,
            "disabled" => Disabled,
            "checked" => Checked,
            "indeterminate" => Indeterminate,
            "read-write" => ReadWrite,
            "read-only" => ReadOnly,
            _ => return Err(())
        };

        if !pseudo_class.is_internal() || self.in_user_agent_stylesheet() {
            Ok(pseudo_class)
        } else {
            Err(())
        }
    }

    fn parse_pseudo_element(&self, name: Cow<str>) -> Result<PseudoElement, ()> {
        match PseudoElement::from_slice(&name, self.in_user_agent_stylesheet()) {
            Some(pseudo) => Ok(pseudo),
            None => Err(()),
        }
    }

    fn default_namespace(&self) -> Option<Namespace> {
        self.namespaces.default.clone()
    }

    fn namespace_for_prefix(&self, prefix: &Atom) -> Option<Namespace> {
        self.namespaces.prefixes.get(prefix).cloned()
    }
}

impl SelectorImpl {
    #[inline]
    /// Returns the kind of cascade type that a given pseudo is going to use.
    ///
    /// In Gecko we only compute ::before and ::after eagerly. We save the rules
    /// for anonymous boxes separately, so we resolve them as precomputed
    /// pseudos.
    ///
    /// We resolve the others lazily, see `Servo_ResolvePseudoStyle`.
    pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
        if Self::pseudo_is_before_or_after(pseudo) {
            return PseudoElementCascadeType::Eager
        }

        if pseudo.is_anon_box() {
            return PseudoElementCascadeType::Precomputed
        }

        PseudoElementCascadeType::Lazy
    }

    #[inline]
    /// Executes a function for each pseudo-element.
    pub fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(PseudoElement),
    {
        macro_rules! pseudo_element {
            ($pseudo_str_with_colon:expr, $atom:expr, $is_anon_box:expr) => {{
                fun(PseudoElement($atom, $is_anon_box));
            }}
        }

        include!("generated/gecko_pseudo_element_helper.rs")
    }

    #[inline]
    /// Returns whether the given pseudo-element is `::before` or `::after`.
    pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
        *pseudo.as_atom() == atom!(":before") ||
        *pseudo.as_atom() == atom!(":after")
    }

    #[inline]
    /// Returns the relevant state flag for a given non-tree-structural
    /// pseudo-class.
    pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
        pc.state_flag()
    }
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many1, sep_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast;

pub fn expr<I>(input: State<I>) -> ParseResult(ast::ExprNode, I)
    where I: Stream<Item=char> {
        unimplemented!()
}

#[cfg(test)]
mod tests {
    use ::ast;
    use super::expr;
    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident"),
            Ok((ast::NameNode { name: "ident" }, ""))
            );
    }

}<commit_msg>Basic parser for names<commit_after>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many, many1, sep_by, satisfy, string,Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast;
use super::ast::ExprNode;

pub fn expr<I>(input: State<I>) -> ParseResult<ast::ExprNode, I>
    where I: Stream<Item=char> {

        let spaces = spaces();
        let name = many1(satisfy(|c| c.is_alphabetic()));
        /* // TODO: fix
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            expr as fn (_) -> _
            );*/
        spaces.clone().with(
             name.map(|it: String| ast::ExprNode::Name(ast::NameNode{ name: it}))
             //.or(sexpr.map(|it| ast::ExprNode::SExpr(ast::SExprNode())))
         ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast;
    use super::expr;
    use super::parser_combinators::{Parser, ParseResult};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident").unwrap(),
            (ast::ExprNode::Name(ast::NameNode { name: "ident".to_string() }), "")
            );
    }

}
<|endoftext|>


<commit_before>pub use svm::slist::List::{Cons,Nil};
use std::fmt;
use std::ops::Index;

/// Convenience macro for making lists.
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// assert_eq!(
///     list!(1i32, 2i32, 3i32),
///     Cons(1i32, Box::new(Cons(2i32, Box::new(Cons(3i32, Box::new(Nil))))))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( @Empty )
);

/// Common functions for an immutable Stack abstract data type.
pub trait Stack<T> {

    /// Push an item to the top of the stack, returning a new stack
    fn push(self, item : T) -> Self;

    /// Pop the top element of the stack. Returns an Option on a T and
    /// a new Stack<T> to replace this.
    fn pop(self)            -> Option<(T, Self)>;

    /// Peek at the top item of the stack.
    ///
    /// Returns Some<T> if there is an item on top of the stack,
    /// and None if the stack is empty.
    fn peek(&self)          -> Option<&T>;

    /// Returns an empty stack.
    fn empty()              -> Self;
}

/// Stack implementation using a cons list
impl<T> Stack<T> for List<T> {

    /// Push an item to the top of the stack, returning a new stack.
    ///
    /// # Examples:
    /// ```
    /// use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// assert_eq!(s.peek(), None);
    /// s = s.push(1);
    /// assert_eq!(s.peek(), Some(&1));
    /// s = s.push(6);
    /// assert_eq!(s.peek(), Some(&6));
    /// ```
    fn push(self, item: T) -> List<T> {
        Cons(item, box self)
    }

    /// Pop the top element of the stack.
    ///
    /// Pop the top element of the stack. Returns an
    /// `Option<(T,List<T>)>` containing the top element and a new
    /// `List<T>` with that item removed, or `None` if the stack is
    /// empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn pop(self) -> Option<(T,List<T>)> {
        match self {
            Cons(item, new_self)    => Some((item, *new_self)),
            Nil                     => None
        }
    }

    fn empty() -> List<T> {
        Nil
    }

    /// Peek at the top element of the stack.
    ///
    /// Peek at the top element of the stack. Returns an `Option<&T>`
    /// with a borrowed pointer to the top element, or `None` if the
    /// stack is empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn peek(&self) -> Option<&T> {
        match self {
            &Nil => None,
            &Cons(ref it,_) => Some(it)
        }
    }

}

/// Singly-linked cons list.
///
/// This is used internally to represent list primitives in the
/// machine.
#[derive(PartialEq,Clone,Debug)]
pub enum List<T> {
    /// Cons cell containing a `T` and a link to the tail
    Cons(T, Box<List<T>>),
    /// The empty list.
    Nil,
}

/// Public implementation for List.
impl<T> List<T> {

    /// Creates a new empty list
    pub fn new() -> List<T> {
        Nil
    }

    /// Prepends the given item to the list.
    ///
    /// Returns the list containing the new  head item.
    /// This is an O(1) operation.
    pub fn prepend(self, it: T) -> List<T> {
        Cons(it, box self)
    }

    /// Appends an item to the end of the list.
    ///
    /// This is an O(n) operation.
    pub fn append(self, it: T) {
        unimplemented!()
    }

    /// Returns the length of the list.
    pub fn length (&self) -> usize {
        match *self {
            Cons(_, ref tail) => 1 + tail.length(),
            Nil => 0
        }
    }

    /// Provide a forward iterator
    #[inline]
    pub fn iter<'a>(&'a self) -> ListIterator<'a, T> {
        ListIterator{current: self}
    }
}

impl<'a, T> fmt::Display for List<T> where T: fmt::Display{

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: replace toString with this
        match *self {
            Cons(ref head, ref tail) => write!(f, "({}, {})", head, tail),
            Nil => write!(f,"nil")
        }
    }
}

/// Wraps a List<T> to allow it to be used as an Iterator<T>
pub struct ListIterator<'a, T:'a> {
    current: &'a List<T>
}

/// Implementation of Iterator for List. This allows iteration by
/// link hopping.
impl<'a, T> Iterator for ListIterator<'a, T> {
    type Item = &'a T;

    /// Get the next element from the list.
    ///
    /// Get the next element from the list. Returns a `Some<T>`, or `Nil`
    /// if at the end of the list.
    ///
    /// # Examples:
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let list = list!(1,2,3);
    /// let mut iter = list.iter();
    /// assert_eq!(iter.next().unwrap(), &1);
    /// assert_eq!(iter.next().unwrap(), &2);
    /// assert_eq!(iter.next().unwrap(), &3);
    /// # }
    /// ```
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let l: List<isize> = list!(1,2,3,4,5,6);
    /// let mut string = String::new();
    /// for item in l.iter() {
    ///     string.push_str((item.to_string() + ", ").as_slice());
    /// }
    /// assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    /// # }
    /// ```
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cons(ref head, box ref tail) => { self.current = tail; Some(head) },
            &Nil => None
        }
    }
}

impl<'a, T> ExactSizeIterator for ListIterator<'a, T> {
    fn len(&self) -> usize {
        self.current.length()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[1us], 1);
/// # }
/// ```
impl<T> Index<usize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        let mut it = self.iter();
        println!("debug, in index, length {}", _index);
        for _ in 0..*_index-1 {
            it.next();
        }
        it.next().unwrap()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[1is], 1);
/// # }
/// ```
impl<T> Index<isize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &isize) -> &'a T {
        let mut it = self.iter();
        for _ in 0..*_index-1 {
            it.next();
        }
        it.next().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::{List, Stack};
    use super::List::{Cons,Nil};

    #[test]
    fn test_list_length() {
        let full_list: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_list: List<i32> = List::new();
        assert_eq!(full_list.length(), 3);
        assert_eq!(empty_list.length(), 0);
    }

    #[test]
    fn test_list_to_string() {
        let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))");
    }

    #[test]
    fn test_stack_length() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.length(), 3);
        assert_eq!(empty_stack.length(), 0);
    }

    #[test]
    fn test_stack_peek() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.peek(), Some(&1));
        assert_eq!(empty_stack.peek(), None);
    }

    #[test]
    fn test_stack_push() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
    }

    #[test]
    fn test_stack_pop() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
        let pop_result = s.pop().unwrap(); // should not break
        s = pop_result.1;
        assert_eq!(s.peek(), Some(&1));
        assert_eq!(pop_result.0, 6);
    }

    #[test]
    fn test_list_indexing() {
        let l: List<int> = list!(1,2,3,4,5,6);
        assert_eq!(l[0us],1);
        assert_eq!(l[1us],2);
        assert_eq!(l[2us],3);
        assert_eq!(l[3us],4);
        assert_eq!(l[4us],5);
        assert_eq!(l[5us],6);
    }

    #[test]
    fn test_list_macro() {
        let l: List<i32> = list!(1i32, 2i32, 3i32);
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))")
    }

    #[test]
    fn test_list_iter() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        let mut string = String::new();
        for item in l.iter() {
            string.push_str((item.to_string() + ", ").as_slice());
        }
        assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    }

}
<commit_msg>Tests for both kinds of list idnexing<commit_after>pub use svm::slist::List::{Cons,Nil};
use std::fmt;
use std::ops::Index;

/// Convenience macro for making lists.
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// assert_eq!(
///     list!(1i32, 2i32, 3i32),
///     Cons(1i32, Box::new(Cons(2i32, Box::new(Cons(3i32, Box::new(Nil))))))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( @Empty )
);

/// Common functions for an immutable Stack abstract data type.
pub trait Stack<T> {

    /// Push an item to the top of the stack, returning a new stack
    fn push(self, item : T) -> Self;

    /// Pop the top element of the stack. Returns an Option on a T and
    /// a new Stack<T> to replace this.
    fn pop(self)            -> Option<(T, Self)>;

    /// Peek at the top item of the stack.
    ///
    /// Returns Some<T> if there is an item on top of the stack,
    /// and None if the stack is empty.
    fn peek(&self)          -> Option<&T>;

    /// Returns an empty stack.
    fn empty()              -> Self;
}

/// Stack implementation using a cons list
impl<T> Stack<T> for List<T> {

    /// Push an item to the top of the stack, returning a new stack.
    ///
    /// # Examples:
    /// ```
    /// use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// assert_eq!(s.peek(), None);
    /// s = s.push(1);
    /// assert_eq!(s.peek(), Some(&1));
    /// s = s.push(6);
    /// assert_eq!(s.peek(), Some(&6));
    /// ```
    fn push(self, item: T) -> List<T> {
        Cons(item, box self)
    }

    /// Pop the top element of the stack.
    ///
    /// Pop the top element of the stack. Returns an
    /// `Option<(T,List<T>)>` containing the top element and a new
    /// `List<T>` with that item removed, or `None` if the stack is
    /// empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn pop(self) -> Option<(T,List<T>)> {
        match self {
            Cons(item, new_self)    => Some((item, *new_self)),
            Nil                     => None
        }
    }

    fn empty() -> List<T> {
        Nil
    }

    /// Peek at the top element of the stack.
    ///
    /// Peek at the top element of the stack. Returns an `Option<&T>`
    /// with a borrowed pointer to the top element, or `None` if the
    /// stack is empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn peek(&self) -> Option<&T> {
        match self {
            &Nil => None,
            &Cons(ref it,_) => Some(it)
        }
    }

}

/// Singly-linked cons list.
///
/// This is used internally to represent list primitives in the
/// machine.
#[derive(PartialEq,Clone,Debug)]
pub enum List<T> {
    /// Cons cell containing a `T` and a link to the tail
    Cons(T, Box<List<T>>),
    /// The empty list.
    Nil,
}

/// Public implementation for List.
impl<T> List<T> {

    /// Creates a new empty list
    pub fn new() -> List<T> {
        Nil
    }

    /// Prepends the given item to the list.
    ///
    /// Returns the list containing the new  head item.
    /// This is an O(1) operation.
    pub fn prepend(self, it: T) -> List<T> {
        Cons(it, box self)
    }

    /// Appends an item to the end of the list.
    ///
    /// This is an O(n) operation.
    pub fn append(self, it: T) {
        unimplemented!()
    }

    /// Returns the length of the list.
    pub fn length (&self) -> usize {
        match *self {
            Cons(_, ref tail) => 1 + tail.length(),
            Nil => 0
        }
    }

    /// Provide a forward iterator
    #[inline]
    pub fn iter<'a>(&'a self) -> ListIterator<'a, T> {
        ListIterator{current: self}
    }
}

impl<'a, T> fmt::Display for List<T> where T: fmt::Display{

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: replace toString with this
        match *self {
            Cons(ref head, ref tail) => write!(f, "({}, {})", head, tail),
            Nil => write!(f,"nil")
        }
    }
}

/// Wraps a List<T> to allow it to be used as an Iterator<T>
pub struct ListIterator<'a, T:'a> {
    current: &'a List<T>
}

/// Implementation of Iterator for List. This allows iteration by
/// link hopping.
impl<'a, T> Iterator for ListIterator<'a, T> {
    type Item = &'a T;

    /// Get the next element from the list.
    ///
    /// Get the next element from the list. Returns a `Some<T>`, or `Nil`
    /// if at the end of the list.
    ///
    /// # Examples:
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let list = list!(1,2,3);
    /// let mut iter = list.iter();
    /// assert_eq!(iter.next().unwrap(), &1);
    /// assert_eq!(iter.next().unwrap(), &2);
    /// assert_eq!(iter.next().unwrap(), &3);
    /// # }
    /// ```
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::svm::slist;
    /// # use seax_svm::svm::slist::List;
    /// # use seax_svm::svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let l: List<isize> = list!(1,2,3,4,5,6);
    /// let mut string = String::new();
    /// for item in l.iter() {
    ///     string.push_str((item.to_string() + ", ").as_slice());
    /// }
    /// assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    /// # }
    /// ```
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cons(ref head, box ref tail) => { self.current = tail; Some(head) },
            &Nil => None
        }
    }
}

impl<'a, T> ExactSizeIterator for ListIterator<'a, T> {
    fn len(&self) -> usize {
        self.current.length()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[1us], 1);
/// # }
/// ```
impl<T> Index<usize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        let mut it = self.iter();
        for _ in range(0,*_index-1) {
            it.next();
        }
        it.next().unwrap()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::svm::slist;
/// # use seax_svm::svm::slist::List;
/// # use seax_svm::svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[1is], 1);
/// # }
/// ```
impl<T> Index<isize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &isize) -> &'a T {
        let mut it = self.iter();
        for _ in 0..*_index-1 {
            it.next();
        }
        it.next().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::{List, Stack};
    use super::List::{Cons,Nil};

    #[test]
    fn test_list_length() {
        let full_list: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_list: List<i32> = List::new();
        assert_eq!(full_list.length(), 3);
        assert_eq!(empty_list.length(), 0);
    }

    #[test]
    fn test_list_to_string() {
        let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))");
    }

    #[test]
    fn test_stack_length() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.length(), 3);
        assert_eq!(empty_stack.length(), 0);
    }

    #[test]
    fn test_stack_peek() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.peek(), Some(&1));
        assert_eq!(empty_stack.peek(), None);
    }

    #[test]
    fn test_stack_push() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
    }

    #[test]
    fn test_stack_pop() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
        let pop_result = s.pop().unwrap(); // should not break
        s = pop_result.1;
        assert_eq!(s.peek(), Some(&1));
        assert_eq!(pop_result.0, 6);
    }

    #[test]
    fn test_list_usize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0us],1);
        assert_eq!(l[1us],2);
        assert_eq!(l[2us],3);
        assert_eq!(l[3us],4);
        assert_eq!(l[4us],5);
        assert_eq!(l[5us],6);
    }

    #[test]
    fn test_list_isize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0is],1);
        assert_eq!(l[1is],2);
        assert_eq!(l[2is],3);
        assert_eq!(l[3is],4);
        assert_eq!(l[4is],5);
        assert_eq!(l[5is],6);
    }

    #[test]
    fn test_list_macro() {
        let l: List<i32> = list!(1i32, 2i32, 3i32);
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))")
    }

    #[test]
    fn test_list_iter() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        let mut string = String::new();
        for item in l.iter() {
            string.push_str((item.to_string() + ", ").as_slice());
        }
        assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    }

}
<|endoftext|>