<commit_before>use std::sync::Arc;

use rustc_hash::{FxHashMap, FxHashSet};
use arrayvec::ArrayVec;
use relative_path::RelativePathBuf;
use ra_db::{FileId, SourceRootId, SourceRoot};
use ra_syntax::{
    SyntaxNode, TreeArc,
    algo::generate,
    ast::{self, AstNode, NameOwner},
};
use ra_arena::{Arena, RawId, impl_arena_id};
use test_utils::tested_by;

use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource};

impl ModuleSource {
    pub(crate) fn from_source_item_id(
        db: &impl HirDatabase,
        source_item_id: SourceItemId,
    ) -> ModuleSource {
        let module_syntax = db.file_item(source_item_id);
        if let Some(source_file) = ast::SourceFile::cast(&module_syntax) {
            ModuleSource::SourceFile(source_file.to_owned())
        } else if let Some(module) = ast::Module::cast(&module_syntax) {
            assert!(module.item_list().is_some(), "expected inline module");
            ModuleSource::Module(module.to_owned())
        } else {
            panic!("expected file or inline module")
        }
    }
}

#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Submodule {
    name: Name,
    is_declaration: bool,
    source: SourceItemId,
}

impl Submodule {
    pub(crate) fn submodules_query(
        db: &impl HirDatabase,
        source: SourceItemId,
    ) -> Arc<Vec<Submodule>> {
        db.check_canceled();
        let file_id = source.file_id;
        let file_items = db.file_items(file_id);
        let module_source = ModuleSource::from_source_item_id(db, source);
        let submodules = match module_source {
            ModuleSource::SourceFile(source_file) => {
                collect_submodules(file_id, &file_items, &*source_file)
            }
            ModuleSource::Module(module) => {
                collect_submodules(file_id, &file_items, module.item_list().unwrap())
            }
        };
        return Arc::new(submodules);

        fn collect_submodules(
            file_id: HirFileId,
            file_items: &SourceFileItems,
            root: &impl ast::ModuleItemOwner,
        ) -> Vec<Submodule> {
            modules(root)
                .map(|(name, m)| Submodule {
                    name,
                    is_declaration: m.has_semi(),
                    source: SourceItemId {
                        file_id,
                        item_id: Some(file_items.id_of(file_id, m.syntax())),
                    },
                })
                .collect()
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModuleId(RawId);
impl_arena_id!(ModuleId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LinkId(RawId);
impl_arena_id!(LinkId);

/// Physically, rust source is organized as a set of files, but logically it is
/// organized as a tree of modules. Usually, a single file corresponds to a
/// single module, but it is not neccessarily always the case.
///
/// `ModuleTree` encapsulates the logic of transitioning from the fuzzy world of files
/// (which can have multiple parents) to the precise world of modules (which
/// always have one parent).
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ModuleTree {
    mods: Arena<ModuleId, ModuleData>,
    links: Arena<LinkId, LinkData>,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ModuleData {
    source: SourceItemId,
    parent: Option<LinkId>,
    children: Vec<LinkId>,
}

#[derive(Hash, Debug, PartialEq, Eq)]
struct LinkData {
    source: SourceItemId,
    owner: ModuleId,
    name: Name,
    points_to: Vec<ModuleId>,
    problem: Option<Problem>,
}

impl ModuleTree {
    pub(crate) fn module_tree_query(
        db: &impl HirDatabase,
        source_root: SourceRootId,
    ) -> Arc<ModuleTree> {
        db.check_canceled();
        let res = create_module_tree(db, source_root);
        Arc::new(res)
    }

    pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
        self.mods.iter().map(|(id, _)| id)
    }

    pub(crate) fn find_module_by_source(&self, source: SourceItemId) -> Option<ModuleId> {
        let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?;
        Some(res)
    }
}

impl ModuleId {
    pub(crate) fn source(self, tree: &ModuleTree) -> SourceItemId {
        tree.mods[self].source
    }
    pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
        tree.mods[self].parent
    }
    pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
        let link = self.parent_link(tree)?;
        Some(tree.links[link].owner)
    }
    pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
        generate(Some(self), move |it| it.parent(tree))
            .last()
            .unwrap()
    }
    pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
        let link = tree.mods[self]
            .children
            .iter()
            .map(|&it| &tree.links[it])
            .find(|it| it.name == *name)?;
        Some(*link.points_to.first()?)
    }
    pub(crate) fn children<'a>(
        self,
        tree: &'a ModuleTree,
    ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
        tree.mods[self].children.iter().filter_map(move |&it| {
            let link = &tree.links[it];
            let module = *link.points_to.first()?;
            Some((link.name.clone(), module))
        })
    }
    pub(crate) fn problems(
        self,
        tree: &ModuleTree,
        db: &impl HirDatabase,
    ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
        tree.mods[self]
            .children
            .iter()
            .filter_map(|&link| {
                let p = tree.links[link].problem.clone()?;
                let s = link.source(tree, db);
                let s = s.name().unwrap().syntax().to_owned();
                Some((s, p))
            })
            .collect()
    }
}

impl LinkId {
    pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
        tree.links[self].owner
    }
    pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
        &tree.links[self].name
    }
    pub(crate) fn source(self, tree: &ModuleTree, db: &impl HirDatabase) -> TreeArc<ast::Module> {
        let syntax_node = db.file_item(tree.links[self].source);
        ast::Module::cast(&syntax_node).unwrap().to_owned()
    }
}

impl ModuleTree {
    fn push_mod(&mut self, data: ModuleData) -> ModuleId {
        self.mods.alloc(data)
    }
    fn push_link(&mut self, data: LinkData) -> LinkId {
        let owner = data.owner;
        let id = self.links.alloc(data);
        self.mods[owner].children.push(id);
        id
    }
}

fn modules(root: &impl ast::ModuleItemOwner) -> impl Iterator<Item = (Name, &ast::Module)> {
    root.items()
        .filter_map(|item| match item.kind() {
            ast::ModuleItemKind::Module(m) => Some(m),
            _ => None,
        })
        .filter_map(|module| {
            let name = module.name()?.as_name();
            if !module.has_semi() && module.item_list().is_none() {
                tested_by!(name_res_works_for_broken_modules);
                return None;
            }
            Some((name, module))
        })
}

fn create_module_tree<'a>(db: &impl HirDatabase, source_root: SourceRootId) -> ModuleTree {
    let mut tree = ModuleTree::default();

    let mut roots = FxHashMap::default();
    let mut visited = FxHashSet::default();

    let source_root = db.source_root(source_root);
    for &file_id in source_root.files.values() {
        let source = SourceItemId {
            file_id: file_id.into(),
            item_id: None,
        };
        if visited.contains(&source) {
            continue; // TODO: use explicit crate_roots here
        }
        assert!(!roots.contains_key(&file_id));
        let module_id = build_subtree(
            db,
            &source_root,
            &mut tree,
            &mut visited,
            &mut roots,
            None,
            source,
        );
        roots.insert(file_id, module_id);
    }
    tree
}

fn build_subtree(
    db: &impl HirDatabase,
    source_root: &SourceRoot,
    tree: &mut ModuleTree,
    visited: &mut FxHashSet<SourceItemId>,
    roots: &mut FxHashMap<FileId, ModuleId>,
    parent: Option<LinkId>,
    source: SourceItemId,
) -> ModuleId {
    visited.insert(source);
    let id = tree.push_mod(ModuleData {
        source,
        parent,
        children: Vec::new(),
    });
    for sub in db.submodules(source).iter() {
        let link = tree.push_link(LinkData {
            source: sub.source,
            name: sub.name.clone(),
            owner: id,
            points_to: Vec::new(),
            problem: None,
        });

        let (points_to, problem) = if sub.is_declaration {
            let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name);
            let points_to = points_to
                .into_iter()
                .map(|file_id| match roots.remove(&file_id) {
                    Some(module_id) => {
                        tree.mods[module_id].parent = Some(link);
                        module_id
                    }
                    None => build_subtree(
                        db,
                        source_root,
                        tree,
                        visited,
                        roots,
                        Some(link),
                        SourceItemId {
                            file_id: file_id.into(),
                            item_id: None,
                        },
                    ),
                })
                .collect::<Vec<_>>();
            (points_to, problem)
        } else {
            let points_to = build_subtree(
                db,
                source_root,
                tree,
                visited,
                roots,
                Some(link),
                sub.source,
            );
            (vec![points_to], None)
        };

        tree.links[link].points_to = points_to;
        tree.links[link].problem = problem;
    }
    id
}

fn resolve_submodule(
    db: &impl HirDatabase,
    file_id: HirFileId,
    name: &Name,
) -> (Vec<FileId>, Option<Problem>) {
    // FIXME: handle submodules of inline modules properly
    let file_id = file_id.original_file(db);
    let source_root_id = db.file_source_root(file_id);
    let path = db.file_relative_path(file_id);
    let root = RelativePathBuf::default();
    let dir_path = path.parent().unwrap_or(&root);
    let mod_name = path.file_stem().unwrap_or("unknown");
    let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";

    let file_mod = dir_path.join(format!("{}.rs", name));
    let dir_mod = dir_path.join(format!("{}/mod.rs", name));
    let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
    let mut candidates = ArrayVec::<[_; 2]>::new();
    if is_dir_owner {
        candidates.push(file_mod.clone());
        candidates.push(dir_mod);
    } else {
        candidates.push(file_dir_mod.clone());
    };
    let sr = db.source_root(source_root_id);
    let points_to = candidates
        .into_iter()
        .filter_map(|path| sr.files.get(&path))
        .map(|&it| it)
        .collect::<Vec<_>>();
    let problem = if points_to.is_empty() {
        Some(Problem::UnresolvedModule {
            candidate: if is_dir_owner { file_mod } else { file_dir_mod },
        })
    } else {
        None
    };
    (points_to, problem)
}
<commit_msg>better names<commit_after>use std::sync::Arc;

use rustc_hash::{FxHashMap, FxHashSet};
use arrayvec::ArrayVec;
use relative_path::RelativePathBuf;
use ra_db::{FileId, SourceRootId, SourceRoot};
use ra_syntax::{
    SyntaxNode, TreeArc,
    algo::generate,
    ast::{self, AstNode, NameOwner},
};
use ra_arena::{Arena, RawId, impl_arena_id};
use test_utils::tested_by;

use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource};

impl ModuleSource {
    pub(crate) fn from_source_item_id(
        db: &impl HirDatabase,
        source_item_id: SourceItemId,
    ) -> ModuleSource {
        let module_syntax = db.file_item(source_item_id);
        if let Some(source_file) = ast::SourceFile::cast(&module_syntax) {
            ModuleSource::SourceFile(source_file.to_owned())
        } else if let Some(module) = ast::Module::cast(&module_syntax) {
            assert!(module.item_list().is_some(), "expected inline module");
            ModuleSource::Module(module.to_owned())
        } else {
            panic!("expected file or inline module")
        }
    }
}

#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Submodule {
    name: Name,
    is_declaration: bool,
    source: SourceItemId,
}

impl Submodule {
    pub(crate) fn submodules_query(
        db: &impl HirDatabase,
        source: SourceItemId,
    ) -> Arc<Vec<Submodule>> {
        db.check_canceled();
        let file_id = source.file_id;
        let file_items = db.file_items(file_id);
        let module_source = ModuleSource::from_source_item_id(db, source);
        let submodules = match module_source {
            ModuleSource::SourceFile(source_file) => {
                collect_submodules(file_id, &file_items, &*source_file)
            }
            ModuleSource::Module(module) => {
                collect_submodules(file_id, &file_items, module.item_list().unwrap())
            }
        };
        return Arc::new(submodules);

        fn collect_submodules(
            file_id: HirFileId,
            file_items: &SourceFileItems,
            root: &impl ast::ModuleItemOwner,
        ) -> Vec<Submodule> {
            modules(root)
                .map(|(name, m)| Submodule {
                    name,
                    is_declaration: m.has_semi(),
                    source: SourceItemId {
                        file_id,
                        item_id: Some(file_items.id_of(file_id, m.syntax())),
                    },
                })
                .collect()
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModuleId(RawId);
impl_arena_id!(ModuleId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LinkId(RawId);
impl_arena_id!(LinkId);

/// Physically, rust source is organized as a set of files, but logically it is
/// organized as a tree of modules. Usually, a single file corresponds to a
/// single module, but it is not neccessarily always the case.
///
/// `ModuleTree` encapsulates the logic of transitioning from the fuzzy world of files
/// (which can have multiple parents) to the precise world of modules (which
/// always have one parent).
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ModuleTree {
    mods: Arena<ModuleId, ModuleData>,
    links: Arena<LinkId, LinkData>,
}

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ModuleData {
    source: SourceItemId,
    parent: Option<LinkId>,
    children: Vec<LinkId>,
}

#[derive(Hash, Debug, PartialEq, Eq)]
struct LinkData {
    source: SourceItemId,
    owner: ModuleId,
    name: Name,
    points_to: Vec<ModuleId>,
    problem: Option<Problem>,
}

impl ModuleTree {
    pub(crate) fn module_tree_query(
        db: &impl HirDatabase,
        source_root: SourceRootId,
    ) -> Arc<ModuleTree> {
        db.check_canceled();
        let res = create_module_tree(db, source_root);
        Arc::new(res)
    }

    pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
        self.mods.iter().map(|(id, _)| id)
    }

    pub(crate) fn find_module_by_source(&self, source: SourceItemId) -> Option<ModuleId> {
        let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?;
        Some(res)
    }

    fn alloc_mod(&mut self, data: ModuleData) -> ModuleId {
        self.mods.alloc(data)
    }

    fn alloc_link(&mut self, data: LinkData) -> LinkId {
        let owner = data.owner;
        let id = self.links.alloc(data);
        self.mods[owner].children.push(id);
        id
    }
}

impl ModuleId {
    pub(crate) fn source(self, tree: &ModuleTree) -> SourceItemId {
        tree.mods[self].source
    }
    pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
        tree.mods[self].parent
    }
    pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
        let link = self.parent_link(tree)?;
        Some(tree.links[link].owner)
    }
    pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
        generate(Some(self), move |it| it.parent(tree))
            .last()
            .unwrap()
    }
    pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
        let link = tree.mods[self]
            .children
            .iter()
            .map(|&it| &tree.links[it])
            .find(|it| it.name == *name)?;
        Some(*link.points_to.first()?)
    }
    pub(crate) fn children<'a>(
        self,
        tree: &'a ModuleTree,
    ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
        tree.mods[self].children.iter().filter_map(move |&it| {
            let link = &tree.links[it];
            let module = *link.points_to.first()?;
            Some((link.name.clone(), module))
        })
    }
    pub(crate) fn problems(
        self,
        tree: &ModuleTree,
        db: &impl HirDatabase,
    ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
        tree.mods[self]
            .children
            .iter()
            .filter_map(|&link| {
                let p = tree.links[link].problem.clone()?;
                let s = link.source(tree, db);
                let s = s.name().unwrap().syntax().to_owned();
                Some((s, p))
            })
            .collect()
    }
}

impl LinkId {
    pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
        tree.links[self].owner
    }
    pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
        &tree.links[self].name
    }
    pub(crate) fn source(self, tree: &ModuleTree, db: &impl HirDatabase) -> TreeArc<ast::Module> {
        let syntax_node = db.file_item(tree.links[self].source);
        ast::Module::cast(&syntax_node).unwrap().to_owned()
    }
}

fn modules(root: &impl ast::ModuleItemOwner) -> impl Iterator<Item = (Name, &ast::Module)> {
    root.items()
        .filter_map(|item| match item.kind() {
            ast::ModuleItemKind::Module(m) => Some(m),
            _ => None,
        })
        .filter_map(|module| {
            let name = module.name()?.as_name();
            if !module.has_semi() && module.item_list().is_none() {
                tested_by!(name_res_works_for_broken_modules);
                return None;
            }
            Some((name, module))
        })
}

fn create_module_tree<'a>(db: &impl HirDatabase, source_root: SourceRootId) -> ModuleTree {
    let mut tree = ModuleTree::default();

    let mut roots = FxHashMap::default();
    let mut visited = FxHashSet::default();

    let source_root = db.source_root(source_root);
    for &file_id in source_root.files.values() {
        let source = SourceItemId {
            file_id: file_id.into(),
            item_id: None,
        };
        if visited.contains(&source) {
            continue; // TODO: use explicit crate_roots here
        }
        assert!(!roots.contains_key(&file_id));
        let module_id = build_subtree(
            db,
            &source_root,
            &mut tree,
            &mut visited,
            &mut roots,
            None,
            source,
        );
        roots.insert(file_id, module_id);
    }
    tree
}

fn build_subtree(
    db: &impl HirDatabase,
    source_root: &SourceRoot,
    tree: &mut ModuleTree,
    visited: &mut FxHashSet<SourceItemId>,
    roots: &mut FxHashMap<FileId, ModuleId>,
    parent: Option<LinkId>,
    source: SourceItemId,
) -> ModuleId {
    visited.insert(source);
    let id = tree.alloc_mod(ModuleData {
        source,
        parent,
        children: Vec::new(),
    });
    for sub in db.submodules(source).iter() {
        let link = tree.alloc_link(LinkData {
            source: sub.source,
            name: sub.name.clone(),
            owner: id,
            points_to: Vec::new(),
            problem: None,
        });

        let (points_to, problem) = if sub.is_declaration {
            let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name);
            let points_to = points_to
                .into_iter()
                .map(|file_id| match roots.remove(&file_id) {
                    Some(module_id) => {
                        tree.mods[module_id].parent = Some(link);
                        module_id
                    }
                    None => build_subtree(
                        db,
                        source_root,
                        tree,
                        visited,
                        roots,
                        Some(link),
                        SourceItemId {
                            file_id: file_id.into(),
                            item_id: None,
                        },
                    ),
                })
                .collect::<Vec<_>>();
            (points_to, problem)
        } else {
            let points_to = build_subtree(
                db,
                source_root,
                tree,
                visited,
                roots,
                Some(link),
                sub.source,
            );
            (vec![points_to], None)
        };

        tree.links[link].points_to = points_to;
        tree.links[link].problem = problem;
    }
    id
}

fn resolve_submodule(
    db: &impl HirDatabase,
    file_id: HirFileId,
    name: &Name,
) -> (Vec<FileId>, Option<Problem>) {
    // FIXME: handle submodules of inline modules properly
    let file_id = file_id.original_file(db);
    let source_root_id = db.file_source_root(file_id);
    let path = db.file_relative_path(file_id);
    let root = RelativePathBuf::default();
    let dir_path = path.parent().unwrap_or(&root);
    let mod_name = path.file_stem().unwrap_or("unknown");
    let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";

    let file_mod = dir_path.join(format!("{}.rs", name));
    let dir_mod = dir_path.join(format!("{}/mod.rs", name));
    let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
    let mut candidates = ArrayVec::<[_; 2]>::new();
    if is_dir_owner {
        candidates.push(file_mod.clone());
        candidates.push(dir_mod);
    } else {
        candidates.push(file_dir_mod.clone());
    };
    let sr = db.source_root(source_root_id);
    let points_to = candidates
        .into_iter()
        .filter_map(|path| sr.files.get(&path))
        .map(|&it| it)
        .collect::<Vec<_>>();
    let problem = if points_to.is_empty() {
        Some(Problem::UnresolvedModule {
            candidate: if is_dir_owner { file_mod } else { file_dir_mod },
        })
    } else {
        None
    };
    (points_to, problem)
}
<|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/.

use std::path::Path;

use dbus::{
    arg::{Array, IterAppend},
    Message,
};
use dbus_tree::{MTSync, MethodErr, MethodInfo, MethodResult, PropInfo, Tree};

use crate::{
    dbus_api::{
        blockdev::create_dbus_blockdev,
        types::{DbusErrorEnum, TData, OK_STRING},
        util::{engine_to_dbus_err_tuple, get_next_arg, option_to_tuple},
    },
    engine::{BlockDevTier, EngineAction, Name, Pool, PoolUuid},
};

pub enum BlockDevOp {
    InitCache,
    AddCache,
    AddData,
}

pub fn pool_operation<F, R>(
    tree: &Tree<MTSync<TData>, TData>,
    object_path: &dbus::Path<'static>,
    closure: F,
) -> Result<R, String>
where
    F: Fn((Name, PoolUuid, &dyn Pool)) -> Result<R, String>,
    R: dbus::arg::Append,
{
    let dbus_context = tree.get_data();

    let pool_path = tree
        .get(object_path)
        .expect("implicit argument must be in tree");

    let pool_uuid = typed_uuid_string_err!(
        pool_path
            .get_data()
            .as_ref()
            .ok_or_else(|| format!("no data for object path {}", object_path))?
            .uuid;
        Pool
    );

    let mutex_lock = dbus_context.engine.blocking_lock();
    let (pool_name, pool) = mutex_lock
        .get_pool(pool_uuid)
        .ok_or_else(|| format!("no pool corresponding to uuid {}", &pool_uuid))?;

    closure((pool_name, pool_uuid, pool))
}

pub fn get_pool_encryption_key_desc(
    m: &MethodInfo<MTSync<TData>, TData>,
) -> Result<(bool, String), String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok(option_to_tuple(
            pool.encryption_info()
                .key_description
                .as_ref()
                .map(|kd| kd.as_application_str().to_string()),
            String::new(),
        ))
    })
}

pub fn get_pool_has_cache(m: &MethodInfo<MTSync<TData>, TData>) -> Result<bool, String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok(pool.has_cache())
    })
}

pub fn get_pool_total_size(m: &MethodInfo<MTSync<TData>, TData>) -> Result<String, String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok((*pool.total_physical_size().bytes()).to_string())
    })
}

pub fn get_pool_total_used(m: &MethodInfo<MTSync<TData>, TData>) -> Result<String, String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        pool.total_physical_used()
            .map_err(|e| e.to_string())
            .map(|size| (*size.bytes()).to_string())
    })
}

pub fn get_pool_clevis_info(
    m: &MethodInfo<MTSync<TData>, TData>,
) -> Result<(bool, (String, String)), String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok(option_to_tuple(
            pool.encryption_info()
                .clevis_info
                .as_ref()
                .map(|(pin, config)| (pin.to_owned(), config.to_string())),
            (String::new(), String::new()),
        ))
    })
}

/// A method shared by all pool interfaces and by all blockdev-adding
/// operations, including cache initialization, which is considered a
/// blockdev-adding operation because when a cache is initialized, the
/// data tier must already contain some block devices. The op parameter
/// determines which method belonging to the engine's Pool interface must
/// be invoked.
// FIXME: We have tried two approaches for dispatching to the proper methods
// in the Pool trait. The first had a lot of code duplication, which was
// a drawback. This approach has significantly less code duplication, but
// requires discovering the state of the cache, whether initialized or not,
// in order to figure out which method to dispatch to. We would like to find
// a third approach, which doesn't have the flaws of the two we've tried.
pub fn add_blockdevs(m: &MethodInfo<MTSync<TData>, TData>, op: BlockDevOp) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let devs: Array<&str, _> = get_next_arg(&mut iter, 0)?;

    let dbus_context = m.tree.get_data();
    let object_path = m.path.get_name();
    let return_message = message.method_return();
    let default_return: (bool, Vec<dbus::Path>) = (false, Vec::new());

    let pool_path = m
        .tree
        .get(object_path)
        .expect("implicit argument must be in tree");
    let pool_uuid = typed_uuid!(
        get_data!(pool_path; default_return; return_message).uuid;
        Pool;
        default_return;
        return_message
    );

    let mut mutex_lock = dbus_context.engine.blocking_lock();
    let (pool_name, pool) = get_mut_pool!(mutex_lock; pool_uuid; default_return; return_message);

    let blockdevs = devs.map(|x| Path::new(x)).collect::<Vec<&Path>>();

    let result = match op {
        BlockDevOp::InitCache => log_action!(pool.init_cache(pool_uuid, &*pool_name, &blockdevs)),
        BlockDevOp::AddCache => {
            log_action!(pool.add_blockdevs(pool_uuid, &*pool_name, &blockdevs, BlockDevTier::Cache))
        }
        BlockDevOp::AddData => {
            log_action!(pool.add_blockdevs(pool_uuid, &*pool_name, &blockdevs, BlockDevTier::Data))
        }
    };
    let msg = match result.map(|bds| bds.changed()) {
        Ok(Some(uuids)) => {
            let return_value = uuids
                .iter()
                .map(|uuid| {
                    // FIXME: To avoid this expect, modify add_blockdevs
                    // so that it returns a mutable reference to each
                    // blockdev created.
                    create_dbus_blockdev(
                        dbus_context,
                        object_path.clone(),
                        *uuid,
                        match op {
                            BlockDevOp::AddData => BlockDevTier::Data,
                            _ => BlockDevTier::Cache,
                        },
                        pool.get_blockdev(*uuid)
                            .expect("just inserted by add_blockdevs")
                            .1,
                    )
                })
                .collect::<Vec<_>>();

            return_message.append3(
                (true, return_value),
                DbusErrorEnum::OK as u16,
                OK_STRING.to_string(),
            )
        }
        Ok(None) => return_message.append3(
            default_return,
            DbusErrorEnum::OK as u16,
            OK_STRING.to_string(),
        ),
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&err);
            return_message.append3(default_return, rc, rs)
        }
    };

    Ok(vec![msg])
}

/// Get a pool property and place it on the D-Bus. The property is
/// found by means of the getter method which takes a reference to a
/// Pool and obtains the property from the pool.
pub fn get_pool_property<F, R>(
    i: &mut IterAppend,
    p: &PropInfo<MTSync<TData>, TData>,
    getter: F,
) -> Result<(), MethodErr>
where
    F: Fn((Name, PoolUuid, &dyn Pool)) -> Result<R, String>,
    R: dbus::arg::Append,
{
    i.append(
        pool_operation(p.tree, p.path.get_name(), getter).map_err(|ref e| MethodErr::failed(e))?,
    );
    Ok(())
}

/// Generate D-Bus representation of name property.
#[inline]
pub fn pool_name_prop(name: &Name) -> String {
    name.to_owned()
}

/// Generate D-Bus representation of encrypted property.
#[inline]
pub fn pool_enc_prop(pool: &dyn Pool) -> bool {
    pool.is_encrypted()
}
<commit_msg>Remove FIXME<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/.

use std::path::Path;

use dbus::{
    arg::{Array, IterAppend},
    Message,
};
use dbus_tree::{MTSync, MethodErr, MethodInfo, MethodResult, PropInfo, Tree};

use crate::{
    dbus_api::{
        blockdev::create_dbus_blockdev,
        types::{DbusErrorEnum, TData, OK_STRING},
        util::{engine_to_dbus_err_tuple, get_next_arg, option_to_tuple},
    },
    engine::{BlockDevTier, EngineAction, Name, Pool, PoolUuid},
};

pub enum BlockDevOp {
    InitCache,
    AddCache,
    AddData,
}

pub fn pool_operation<F, R>(
    tree: &Tree<MTSync<TData>, TData>,
    object_path: &dbus::Path<'static>,
    closure: F,
) -> Result<R, String>
where
    F: Fn((Name, PoolUuid, &dyn Pool)) -> Result<R, String>,
    R: dbus::arg::Append,
{
    let dbus_context = tree.get_data();

    let pool_path = tree
        .get(object_path)
        .expect("implicit argument must be in tree");

    let pool_uuid = typed_uuid_string_err!(
        pool_path
            .get_data()
            .as_ref()
            .ok_or_else(|| format!("no data for object path {}", object_path))?
            .uuid;
        Pool
    );

    let mutex_lock = dbus_context.engine.blocking_lock();
    let (pool_name, pool) = mutex_lock
        .get_pool(pool_uuid)
        .ok_or_else(|| format!("no pool corresponding to uuid {}", &pool_uuid))?;

    closure((pool_name, pool_uuid, pool))
}

pub fn get_pool_encryption_key_desc(
    m: &MethodInfo<MTSync<TData>, TData>,
) -> Result<(bool, String), String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok(option_to_tuple(
            pool.encryption_info()
                .key_description
                .as_ref()
                .map(|kd| kd.as_application_str().to_string()),
            String::new(),
        ))
    })
}

pub fn get_pool_has_cache(m: &MethodInfo<MTSync<TData>, TData>) -> Result<bool, String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok(pool.has_cache())
    })
}

pub fn get_pool_total_size(m: &MethodInfo<MTSync<TData>, TData>) -> Result<String, String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok((*pool.total_physical_size().bytes()).to_string())
    })
}

pub fn get_pool_total_used(m: &MethodInfo<MTSync<TData>, TData>) -> Result<String, String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        pool.total_physical_used()
            .map_err(|e| e.to_string())
            .map(|size| (*size.bytes()).to_string())
    })
}

pub fn get_pool_clevis_info(
    m: &MethodInfo<MTSync<TData>, TData>,
) -> Result<(bool, (String, String)), String> {
    pool_operation(m.tree, m.path.get_name(), |(_, _, pool)| {
        Ok(option_to_tuple(
            pool.encryption_info()
                .clevis_info
                .as_ref()
                .map(|(pin, config)| (pin.to_owned(), config.to_string())),
            (String::new(), String::new()),
        ))
    })
}

/// A method shared by all pool interfaces and by all blockdev-adding
/// operations, including cache initialization, which is considered a
/// blockdev-adding operation because when a cache is initialized, the
/// data tier must already contain some block devices. The op parameter
/// determines which method belonging to the engine's Pool interface must
/// be invoked.
pub fn add_blockdevs(m: &MethodInfo<MTSync<TData>, TData>, op: BlockDevOp) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let devs: Array<&str, _> = get_next_arg(&mut iter, 0)?;

    let dbus_context = m.tree.get_data();
    let object_path = m.path.get_name();
    let return_message = message.method_return();
    let default_return: (bool, Vec<dbus::Path>) = (false, Vec::new());

    let pool_path = m
        .tree
        .get(object_path)
        .expect("implicit argument must be in tree");
    let pool_uuid = typed_uuid!(
        get_data!(pool_path; default_return; return_message).uuid;
        Pool;
        default_return;
        return_message
    );

    let mut mutex_lock = dbus_context.engine.blocking_lock();
    let (pool_name, pool) = get_mut_pool!(mutex_lock; pool_uuid; default_return; return_message);

    let blockdevs = devs.map(|x| Path::new(x)).collect::<Vec<&Path>>();

    let result = match op {
        BlockDevOp::InitCache => log_action!(pool.init_cache(pool_uuid, &*pool_name, &blockdevs)),
        BlockDevOp::AddCache => {
            log_action!(pool.add_blockdevs(pool_uuid, &*pool_name, &blockdevs, BlockDevTier::Cache))
        }
        BlockDevOp::AddData => {
            log_action!(pool.add_blockdevs(pool_uuid, &*pool_name, &blockdevs, BlockDevTier::Data))
        }
    };
    let msg = match result.map(|bds| bds.changed()) {
        Ok(Some(uuids)) => {
            let return_value = uuids
                .iter()
                .map(|uuid| {
                    // FIXME: To avoid this expect, modify add_blockdevs
                    // so that it returns a mutable reference to each
                    // blockdev created.
                    create_dbus_blockdev(
                        dbus_context,
                        object_path.clone(),
                        *uuid,
                        match op {
                            BlockDevOp::AddData => BlockDevTier::Data,
                            _ => BlockDevTier::Cache,
                        },
                        pool.get_blockdev(*uuid)
                            .expect("just inserted by add_blockdevs")
                            .1,
                    )
                })
                .collect::<Vec<_>>();

            return_message.append3(
                (true, return_value),
                DbusErrorEnum::OK as u16,
                OK_STRING.to_string(),
            )
        }
        Ok(None) => return_message.append3(
            default_return,
            DbusErrorEnum::OK as u16,
            OK_STRING.to_string(),
        ),
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&err);
            return_message.append3(default_return, rc, rs)
        }
    };

    Ok(vec![msg])
}

/// Get a pool property and place it on the D-Bus. The property is
/// found by means of the getter method which takes a reference to a
/// Pool and obtains the property from the pool.
pub fn get_pool_property<F, R>(
    i: &mut IterAppend,
    p: &PropInfo<MTSync<TData>, TData>,
    getter: F,
) -> Result<(), MethodErr>
where
    F: Fn((Name, PoolUuid, &dyn Pool)) -> Result<R, String>,
    R: dbus::arg::Append,
{
    i.append(
        pool_operation(p.tree, p.path.get_name(), getter).map_err(|ref e| MethodErr::failed(e))?,
    );
    Ok(())
}

/// Generate D-Bus representation of name property.
#[inline]
pub fn pool_name_prop(name: &Name) -> String {
    name.to_owned()
}

/// Generate D-Bus representation of encrypted property.
#[inline]
pub fn pool_enc_prop(pool: &dyn Pool) -> bool {
    pool.is_encrypted()
}
<|endoftext|>


<commit_before>extern crate uuid;
use coin_cbc;

use dsl::LpExpression::*;
use dsl::*;
use solvers::{Solution, SolverTrait, Status, WithMaxSeconds, WithNbThreads};
use std::collections::HashMap;

/// Solver that calls cbc through [rust bindings](https://github.com/KardinalAI/coin_cbc)
#[derive(Debug, Clone, Default)]
pub struct NativeCbcSolver {
    name: String,
    threads: Option<u32>,
    seconds: Option<u32>,
}

impl NativeCbcSolver {
    pub fn new() -> NativeCbcSolver {
        NativeCbcSolver {
            name: "CbcNative".to_string(),
            threads: None,
            seconds: None,
        }
    }
}

impl WithMaxSeconds<NativeCbcSolver> for NativeCbcSolver {
    fn max_seconds(&self) -> Option<u32> {
        self.seconds
    }
    fn with_max_seconds(&self, seconds: u32) -> NativeCbcSolver {
        NativeCbcSolver {
            seconds: Some(seconds),
            ..self.clone()
        }
    }
}
impl WithNbThreads<NativeCbcSolver> for NativeCbcSolver {
    fn nb_threads(&self) -> Option<u32> {
        self.threads
    }
    fn with_nb_threads(&self, threads: u32) -> NativeCbcSolver {
        NativeCbcSolver {
            threads: Some(threads),
            ..self.clone()
        }
    }
}

fn var_lit(expr: &LpExpression, lst: &mut Vec<(String, f32)>) {
    match expr {
        &ConsBin(LpBinary { ref name, .. })
        | &ConsInt(LpInteger { ref name, .. })
        | &ConsCont(LpContinuous { ref name, .. }) => {
            println!("{:?}", (name.clone(), split_constant_and_expr(expr).0));
            lst.push((name.clone(), split_constant_and_expr(expr).0));
        }

        MulExpr(val, ref e) => match **e {
            ConsBin(LpBinary { ref name, .. })
            | ConsInt(LpInteger { ref name, .. })
            | ConsCont(LpContinuous { ref name, .. }) => {
                if let LitVal(lit) = *val.clone() {
                    lst.push((name.clone(), lit))
                }
            }
            MulExpr(..) | AddExpr(..) => var_lit(&*e, lst),
            _ => (),
        },
        &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
            var_lit(&*e1, lst);
            var_lit(&*e2, lst);
        }
        _ => (),
    }
}

fn always_literal(expr: &LpExpression) -> f64 {
    match *expr {
        LitVal(num) => num as f64,
        _ => panic!("wrong generalization"),
    }
}

fn add_variable(m: &mut coin_cbc::Model, expr: &LpExpression) -> coin_cbc::Col {
    match expr {
        ConsInt(LpInteger {
            name: _,
            lower_bound,
            upper_bound,
        }) => {
            let col = m.add_integer();
            if let Some(lb) = lower_bound {
                m.set_col_lower(col, *lb as f64)
            }
            if let Some(ub) = upper_bound {
                m.set_col_lower(col, *ub as f64)
            }
            col
        }
        ConsCont(LpContinuous {
            name: _,
            lower_bound,
            upper_bound,
        }) => {
            let col = m.add_col();
            if let Some(lb) = lower_bound {
                m.set_col_lower(col, *lb as f64)
            }
            if let Some(ub) = upper_bound {
                m.set_col_lower(col, *ub as f64)
            }
            col
        }
        ConsBin(_) => m.add_binary(),
        _ => panic!("Unexpected LpExpression on LpProblem.variables()!"),
    }
}

impl SolverTrait for NativeCbcSolver {
    type P = LpProblem;

    fn run<'a>(&self, problem: &'a Self::P) -> Result<Solution<'a>, String> {
        let mut m = coin_cbc::Model::default();
        // columns (variables)
        let cols: HashMap<String, coin_cbc::Col> = problem
            .variables()
            .iter()
            .map(|(name, expr)| (name.clone(), add_variable(&mut m, expr)))
            .collect();
        // rows (constraints)
        problem.constraints.iter().for_each(|cons| {
            let row = m.add_row();
            let general = cons.generalize();
            match general.1 {
                Constraint::GreaterOrEqual => m.set_row_lower(row, always_literal(&general.2)),
                Constraint::LessOrEqual => m.set_row_upper(row, always_literal(&general.2)),
                Constraint::Equal => m.set_row_equal(row, always_literal(&general.2)),
            }
            let mut lst: Vec<_> = Vec::new();
            var_lit(&general.0, &mut lst);
            println!("{:?}", lst);
            lst.iter()
                .for_each(|(n, lit)| m.set_weight(row, cols[n], *lit as f64));
        });
        // objective
        if let Some(objective) = &problem.obj_expr {
            let mut lst: Vec<_> = Vec::new();
            var_lit(&objective, &mut lst);
            lst.iter()
                .for_each(|(n, lit)| m.set_obj_coeff(cols[n], *lit as f64))
        }
        m.set_obj_sense(match problem.objective_type {
            LpObjective::Maximize => coin_cbc::Sense::Maximize,
            LpObjective::Minimize => coin_cbc::Sense::Minimize,
        });

        let sol = m.solve();

        let mut lst: Vec<_> = Vec::new();
        var_lit(&(problem.obj_expr.clone().unwrap()), &mut lst);

        Ok(Solution {
            status: match sol.raw().status() {
                coin_cbc::raw::Status::Finished => Status::Optimal,
                coin_cbc::raw::Status::Abandoned => Status::Infeasible,
                _ => Status::NotSolved,
            },
            results: cols
                .iter()
                .map(|(name, col)| (name.to_owned(), sol.col(*col) as f32))
                .collect(),
            related_problem: Some(problem),
        })
    }
}
<commit_msg>Remove print statements<commit_after>extern crate uuid;
use coin_cbc;

use dsl::LpExpression::*;
use dsl::*;
use solvers::{Solution, SolverTrait, Status, WithMaxSeconds, WithNbThreads};
use std::collections::HashMap;

/// Solver that calls cbc through [rust bindings](https://github.com/KardinalAI/coin_cbc)
#[derive(Debug, Clone, Default)]
pub struct NativeCbcSolver {
    name: String,
    threads: Option<u32>,
    seconds: Option<u32>,
}

impl NativeCbcSolver {
    pub fn new() -> NativeCbcSolver {
        NativeCbcSolver {
            name: "CbcNative".to_string(),
            threads: None,
            seconds: None,
        }
    }
}

impl WithMaxSeconds<NativeCbcSolver> for NativeCbcSolver {
    fn max_seconds(&self) -> Option<u32> {
        self.seconds
    }
    fn with_max_seconds(&self, seconds: u32) -> NativeCbcSolver {
        NativeCbcSolver {
            seconds: Some(seconds),
            ..self.clone()
        }
    }
}
impl WithNbThreads<NativeCbcSolver> for NativeCbcSolver {
    fn nb_threads(&self) -> Option<u32> {
        self.threads
    }
    fn with_nb_threads(&self, threads: u32) -> NativeCbcSolver {
        NativeCbcSolver {
            threads: Some(threads),
            ..self.clone()
        }
    }
}

fn var_lit(expr: &LpExpression, lst: &mut Vec<(String, f32)>) {
    match expr {
        &ConsBin(LpBinary { ref name, .. })
        | &ConsInt(LpInteger { ref name, .. })
        | &ConsCont(LpContinuous { ref name, .. }) => {
            lst.push((name.clone(), split_constant_and_expr(expr).0));
        }

        MulExpr(val, ref e) => match **e {
            ConsBin(LpBinary { ref name, .. })
            | ConsInt(LpInteger { ref name, .. })
            | ConsCont(LpContinuous { ref name, .. }) => {
                if let LitVal(lit) = *val.clone() {
                    lst.push((name.clone(), lit))
                }
            }
            MulExpr(..) | AddExpr(..) => var_lit(&*e, lst),
            _ => (),
        },
        &AddExpr(ref e1, ref e2) | &SubExpr(ref e1, ref e2) => {
            var_lit(&*e1, lst);
            var_lit(&*e2, lst);
        }
        _ => (),
    }
}

fn always_literal(expr: &LpExpression) -> f64 {
    match *expr {
        LitVal(num) => num as f64,
        _ => panic!("wrong generalization"),
    }
}

fn add_variable(m: &mut coin_cbc::Model, expr: &LpExpression) -> coin_cbc::Col {
    match expr {
        ConsInt(LpInteger {
            name: _,
            lower_bound,
            upper_bound,
        }) => {
            let col = m.add_integer();
            if let Some(lb) = lower_bound {
                m.set_col_lower(col, *lb as f64)
            }
            if let Some(ub) = upper_bound {
                m.set_col_lower(col, *ub as f64)
            }
            col
        }
        ConsCont(LpContinuous {
            name: _,
            lower_bound,
            upper_bound,
        }) => {
            let col = m.add_col();
            if let Some(lb) = lower_bound {
                m.set_col_lower(col, *lb as f64)
            }
            if let Some(ub) = upper_bound {
                m.set_col_lower(col, *ub as f64)
            }
            col
        }
        ConsBin(_) => m.add_binary(),
        _ => panic!("Unexpected LpExpression on LpProblem.variables()!"),
    }
}

impl SolverTrait for NativeCbcSolver {
    type P = LpProblem;

    fn run<'a>(&self, problem: &'a Self::P) -> Result<Solution<'a>, String> {
        let mut m = coin_cbc::Model::default();
        // columns (variables)
        let cols: HashMap<String, coin_cbc::Col> = problem
            .variables()
            .iter()
            .map(|(name, expr)| (name.clone(), add_variable(&mut m, expr)))
            .collect();
        // rows (constraints)
        problem.constraints.iter().for_each(|cons| {
            let row = m.add_row();
            let general = cons.generalize();
            match general.1 {
                Constraint::GreaterOrEqual => m.set_row_lower(row, always_literal(&general.2)),
                Constraint::LessOrEqual => m.set_row_upper(row, always_literal(&general.2)),
                Constraint::Equal => m.set_row_equal(row, always_literal(&general.2)),
            }
            let mut lst: Vec<_> = Vec::new();
            var_lit(&general.0, &mut lst);
            lst.iter()
                .for_each(|(n, lit)| m.set_weight(row, cols[n], *lit as f64));
        });
        // objective
        if let Some(objective) = &problem.obj_expr {
            let mut lst: Vec<_> = Vec::new();
            var_lit(&objective, &mut lst);
            lst.iter()
                .for_each(|(n, lit)| m.set_obj_coeff(cols[n], *lit as f64))
        }
        m.set_obj_sense(match problem.objective_type {
            LpObjective::Maximize => coin_cbc::Sense::Maximize,
            LpObjective::Minimize => coin_cbc::Sense::Minimize,
        });

        let sol = m.solve();

        let mut lst: Vec<_> = Vec::new();
        var_lit(&(problem.obj_expr.clone().unwrap()), &mut lst);

        Ok(Solution {
            status: match sol.raw().status() {
                coin_cbc::raw::Status::Finished => Status::Optimal,
                coin_cbc::raw::Status::Abandoned => Status::Infeasible,
                _ => Status::NotSolved,
            },
            results: cols
                .iter()
                .map(|(name, col)| (name.to_owned(), sol.col(*col) as f32))
                .collect(),
            related_problem: Some(problem),
        })
    }
}
<|endoftext|>


<commit_before>use {Result, Error, from_ffi};
use super::{ffi, consts, GetSockOpt, SetSockOpt};
use errno::Errno;
use sys::time::TimeVal;
use libc::{c_int, uint8_t, c_void, socklen_t};
use std::mem;
use std::os::unix::io::RawFd;

macro_rules! setsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        impl SetSockOpt for $name {
            type Val = $ty;

            fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
                unsafe {
                    let setter: $setter = Set::new(val);

                    let res = ffi::setsockopt(fd, $level, $flag,
                                              setter.ffi_ptr(),
                                              setter.ffi_len());
                    from_ffi(res)
                }
            }
        }
    }
}

macro_rules! getsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        impl GetSockOpt for $name {
            type Val = $ty;

            fn get(&self, fd: RawFd) -> Result<$ty> {
                unsafe {
                    let mut getter: $getter = Get::blank();

                    let res = ffi::getsockopt(fd, $level, $flag,
                                              getter.ffi_ptr(),
                                              getter.ffi_len());
                    if res < 0 {
                        return Err(Error::Sys(Errno::last()));
                    }

                    Ok(getter.unwrap())
                }
            }
        }
    }
}

// Helper to generate the sockopt accessors
macro_rules! sockopt_impl {
    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (Both, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
    };

    (Both, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
    };
}

/*
 *
 * ===== Define sockopts =====
 *
 */

sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool);
sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool);
sockopt_impl!(Both, TcpNoDelay, consts::SOL_SOCKET, consts::TCP_NODELAY, bool);
sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger);
sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8);
sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool);
sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal);
sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal);
sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool);
sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool);
sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32);
sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool);
#[cfg(any(target_os = "macos",
          target_os = "ios"))]
sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32);
#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "linux",
          target_os = "android",
          target_os = "nacl"))]
sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32);

/*
 *
 * ===== Accessor helpers =====
 *
 */

trait Get<T> {
    unsafe fn blank() -> Self;
    unsafe fn ffi_ptr(&mut self) -> *mut c_void;
    unsafe fn ffi_len(&mut self) -> *mut socklen_t;
    unsafe fn unwrap(self) -> T;
}

trait Set<'a, T> {
    fn new(val: &'a T) -> Self;
    unsafe fn ffi_ptr(&self) -> *const c_void;
    unsafe fn ffi_len(&self) -> socklen_t;
}

struct GetStruct<T> {
    len: socklen_t,
    val: T,
}

impl<T> Get<T> for GetStruct<T> {
    unsafe fn blank() -> Self {
        GetStruct {
            len: mem::size_of::<T>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> T {
        assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
        self.val
    }
}

struct SetStruct<'a, T: 'static> {
    ptr: &'a T,
}

impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
    fn new(ptr: &'a T) -> SetStruct<'a, T> {
        SetStruct { ptr: ptr }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(self.ptr)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<T>() as socklen_t
    }
}

struct GetBool {
    len: socklen_t,
    val: c_int,
}

impl Get<bool> for GetBool {
    unsafe fn blank() -> Self {
        GetBool {
            len: mem::size_of::<c_int>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> bool {
        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
        self.val != 0
    }
}

struct SetBool {
    val: c_int,
}

impl<'a> Set<'a, bool> for SetBool {
    fn new(val: &'a bool) -> SetBool {
        SetBool { val: if *val { 1 } else { 0 } }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

struct GetU8 {
    len: socklen_t,
    val: uint8_t,
}

impl Get<u8> for GetU8 {
    unsafe fn blank() -> Self {
        GetU8 {
            len: mem::size_of::<uint8_t>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> u8 {
        assert!(self.len as usize == mem::size_of::<uint8_t>(), "invalid getsockopt implementation");
        self.val as u8
    }
}

struct SetU8 {
    val: uint8_t,
}

impl<'a> Set<'a, u8> for SetU8 {
    fn new(val: &'a u8) -> SetU8 {
        SetU8 { val: *val as uint8_t }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}
<commit_msg>TCP_NODELAY should be in IPPROTO_TCP level<commit_after>use {Result, Error, from_ffi};
use super::{ffi, consts, GetSockOpt, SetSockOpt};
use errno::Errno;
use sys::time::TimeVal;
use libc::{c_int, uint8_t, c_void, socklen_t};
use std::mem;
use std::os::unix::io::RawFd;

macro_rules! setsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        impl SetSockOpt for $name {
            type Val = $ty;

            fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
                unsafe {
                    let setter: $setter = Set::new(val);

                    let res = ffi::setsockopt(fd, $level, $flag,
                                              setter.ffi_ptr(),
                                              setter.ffi_len());
                    from_ffi(res)
                }
            }
        }
    }
}

macro_rules! getsockopt_impl {
    ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        impl GetSockOpt for $name {
            type Val = $ty;

            fn get(&self, fd: RawFd) -> Result<$ty> {
                unsafe {
                    let mut getter: $getter = Get::blank();

                    let res = ffi::getsockopt(fd, $level, $flag,
                                              getter.ffi_ptr(),
                                              getter.ffi_len());
                    if res < 0 {
                        return Err(Error::Sys(Errno::last()));
                    }

                    Ok(getter.unwrap())
                }
            }
        }
    }
}

// Helper to generate the sockopt accessors
macro_rules! sockopt_impl {
    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
    };

    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
    };

    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $name;

        setsockopt_impl!($name, $level, $flag, $ty, $setter);
        getsockopt_impl!($name, $level, $flag, $ty, $getter);
    };

    (Both, $name:ident, $level:path, $flag:path, bool) => {
        sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
    };

    (Both, $name:ident, $level:path, $flag:path, u8) => {
        sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
    };

    (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
        sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
    };
}

/*
 *
 * ===== Define sockopts =====
 *
 */

sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool);
sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool);
sockopt_impl!(Both, TcpNoDelay, consts::IPPROTO_TCP, consts::TCP_NODELAY, bool);
sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger);
sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8);
sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool);
sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal);
sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal);
sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool);
sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool);
sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32);
sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool);
#[cfg(any(target_os = "macos",
          target_os = "ios"))]
sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32);
#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "linux",
          target_os = "android",
          target_os = "nacl"))]
sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32);

/*
 *
 * ===== Accessor helpers =====
 *
 */

trait Get<T> {
    unsafe fn blank() -> Self;
    unsafe fn ffi_ptr(&mut self) -> *mut c_void;
    unsafe fn ffi_len(&mut self) -> *mut socklen_t;
    unsafe fn unwrap(self) -> T;
}

trait Set<'a, T> {
    fn new(val: &'a T) -> Self;
    unsafe fn ffi_ptr(&self) -> *const c_void;
    unsafe fn ffi_len(&self) -> socklen_t;
}

struct GetStruct<T> {
    len: socklen_t,
    val: T,
}

impl<T> Get<T> for GetStruct<T> {
    unsafe fn blank() -> Self {
        GetStruct {
            len: mem::size_of::<T>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> T {
        assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
        self.val
    }
}

struct SetStruct<'a, T: 'static> {
    ptr: &'a T,
}

impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
    fn new(ptr: &'a T) -> SetStruct<'a, T> {
        SetStruct { ptr: ptr }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(self.ptr)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<T>() as socklen_t
    }
}

struct GetBool {
    len: socklen_t,
    val: c_int,
}

impl Get<bool> for GetBool {
    unsafe fn blank() -> Self {
        GetBool {
            len: mem::size_of::<c_int>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> bool {
        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
        self.val != 0
    }
}

struct SetBool {
    val: c_int,
}

impl<'a> Set<'a, bool> for SetBool {
    fn new(val: &'a bool) -> SetBool {
        SetBool { val: if *val { 1 } else { 0 } }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}

struct GetU8 {
    len: socklen_t,
    val: uint8_t,
}

impl Get<u8> for GetU8 {
    unsafe fn blank() -> Self {
        GetU8 {
            len: mem::size_of::<uint8_t>() as socklen_t,
            val: mem::zeroed(),
        }
    }

    unsafe fn ffi_ptr(&mut self) -> *mut c_void {
        mem::transmute(&mut self.val)
    }

    unsafe fn ffi_len(&mut self) -> *mut socklen_t {
        mem::transmute(&mut self.len)
    }

    unsafe fn unwrap(self) -> u8 {
        assert!(self.len as usize == mem::size_of::<uint8_t>(), "invalid getsockopt implementation");
        self.val as u8
    }
}

struct SetU8 {
    val: uint8_t,
}

impl<'a> Set<'a, u8> for SetU8 {
    fn new(val: &'a u8) -> SetU8 {
        SetU8 { val: *val as uint8_t }
    }

    unsafe fn ffi_ptr(&self) -> *const c_void {
        mem::transmute(&self.val)
    }

    unsafe fn ffi_len(&self) -> socklen_t {
        mem::size_of::<c_int>() as socklen_t
    }
}
<|endoftext|>


<commit_before>// ignore-tidy-linelength
// compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats

#![allow(unused)]

struct Test(i32);

impl Test {
    // Make sure we run the pass on a method, not just on bare functions.
    fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 { x }
    fn foo_shr<'x>(&self, x: &'x i32) -> &'x i32 { x }
}

impl Drop for Test {
    fn drop(&mut self) {}
}

fn main() {
    let mut x = 0;
    {
        let v = Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor
        let w = { v }; // assignment
        let w = w; // reborrow
        // escape-to-raw (mut)
        let _w = w as *mut _;
    }

    // Also test closures
    let c: fn(&i32) -> &i32 = |x: &i32| -> &i32 { let _y = x; x };
    let _w = c(&x);

    // need to call `foo_shr` or it doesn't even get generated
    Test(0).foo_shr(&0);

    // escape-to-raw (shr)
    let _w = _w as *const _;
}

// END RUST SOURCE
// START rustc.{{impl}}-foo.EraseRegions.after.mir
//     bb0: {
//         Retag([fn entry] _1);
//         Retag([fn entry] _2);
//         ...
//         _0 = &mut (*_3);
//         Retag(_0);
//         ...
//         return;
//     }
// END rustc.{{impl}}-foo.EraseRegions.after.mir
// START rustc.{{impl}}-foo_shr.EraseRegions.after.mir
//     bb0: {
//         Retag([fn entry] _1);
//         Retag([fn entry] _2);
//         ...
//         _0 = _2;
//         Retag(_0);
//         ...
//         return;
//     }
// END rustc.{{impl}}-foo_shr.EraseRegions.after.mir
// START rustc.main.EraseRegions.after.mir
// fn main() -> () {
//     ...
//     bb0: {
//         ...
//         _3 = const Test::foo(move _4, move _6) -> [return: bb2, unwind: bb3];
//     }
//
//     ...
//
//     bb2: {
//         Retag(_3);
//         ...
//         _9 = move _3;
//         Retag(_9);
//         _8 = &mut (*_9);
//         Retag(_8);
//         StorageDead(_9);
//         StorageLive(_10);
//         _10 = move _8;
//         Retag(_10);
//         ...
//         _13 = &mut (*_10);
//         Retag(_13);
//         _12 = move _13 as *mut i32 (Misc);
//         Retag([raw] _12);
//         ...
//         _16 = move _17(move _18) -> bb5;
//     }
//
//     bb5: {
//         Retag(_16);
//         ...
//         _20 = const Test::foo_shr(move _21, move _23) -> [return: bb6, unwind: bb7];
//     }
//
//     ...
// }
// END rustc.main.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(22), local_id: 72 }], _2: &i32) -> &i32 {
//     ...
//     bb0: {
//         Retag([fn entry] _1);
//         Retag([fn entry] _2);
//         StorageLive(_3);
//         _3 = _2;
//         Retag(_3);
//         _0 = _2;
//         Retag(_0);
//         StorageDead(_3);
//         return;
//     }
// }
// END rustc.main-{{closure}}.EraseRegions.after.mir
// START rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir
// fn  std::ptr::real_drop_in_place(_1: &mut Test) -> () {
//     ...
//     bb0: {
//         Retag([raw] _1);
//         _2 = &mut (*_1);
//         _3 = const <Test as std::ops::Drop>::drop(move _2) -> bb1;
//     }
//
//     bb1: {
//         return;
//     }
// }
// END rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir
<commit_msg>ignore tests on wasm32-bare<commit_after>// ignore-wasm32-bare compiled with panic=abort by default
// ignore-tidy-linelength
// compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats

#![allow(unused)]

struct Test(i32);

impl Test {
    // Make sure we run the pass on a method, not just on bare functions.
    fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 { x }
    fn foo_shr<'x>(&self, x: &'x i32) -> &'x i32 { x }
}

impl Drop for Test {
    fn drop(&mut self) {}
}

fn main() {
    let mut x = 0;
    {
        let v = Test(0).foo(&mut x); // just making sure we do not panic when there is a tuple struct ctor
        let w = { v }; // assignment
        let w = w; // reborrow
        // escape-to-raw (mut)
        let _w = w as *mut _;
    }

    // Also test closures
    let c: fn(&i32) -> &i32 = |x: &i32| -> &i32 { let _y = x; x };
    let _w = c(&x);

    // need to call `foo_shr` or it doesn't even get generated
    Test(0).foo_shr(&0);

    // escape-to-raw (shr)
    let _w = _w as *const _;
}

// END RUST SOURCE
// START rustc.{{impl}}-foo.EraseRegions.after.mir
//     bb0: {
//         Retag([fn entry] _1);
//         Retag([fn entry] _2);
//         ...
//         _0 = &mut (*_3);
//         Retag(_0);
//         ...
//         return;
//     }
// END rustc.{{impl}}-foo.EraseRegions.after.mir
// START rustc.{{impl}}-foo_shr.EraseRegions.after.mir
//     bb0: {
//         Retag([fn entry] _1);
//         Retag([fn entry] _2);
//         ...
//         _0 = _2;
//         Retag(_0);
//         ...
//         return;
//     }
// END rustc.{{impl}}-foo_shr.EraseRegions.after.mir
// START rustc.main.EraseRegions.after.mir
// fn main() -> () {
//     ...
//     bb0: {
//         ...
//         _3 = const Test::foo(move _4, move _6) -> [return: bb2, unwind: bb3];
//     }
//
//     ...
//
//     bb2: {
//         Retag(_3);
//         ...
//         _9 = move _3;
//         Retag(_9);
//         _8 = &mut (*_9);
//         Retag(_8);
//         StorageDead(_9);
//         StorageLive(_10);
//         _10 = move _8;
//         Retag(_10);
//         ...
//         _13 = &mut (*_10);
//         Retag(_13);
//         _12 = move _13 as *mut i32 (Misc);
//         Retag([raw] _12);
//         ...
//         _16 = move _17(move _18) -> bb5;
//     }
//
//     bb5: {
//         Retag(_16);
//         ...
//         _20 = const Test::foo_shr(move _21, move _23) -> [return: bb6, unwind: bb7];
//     }
//
//     ...
// }
// END rustc.main.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(22), local_id: 72 }], _2: &i32) -> &i32 {
//     ...
//     bb0: {
//         Retag([fn entry] _1);
//         Retag([fn entry] _2);
//         StorageLive(_3);
//         _3 = _2;
//         Retag(_3);
//         _0 = _2;
//         Retag(_0);
//         StorageDead(_3);
//         return;
//     }
// }
// END rustc.main-{{closure}}.EraseRegions.after.mir
// START rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir
// fn  std::ptr::real_drop_in_place(_1: &mut Test) -> () {
//     ...
//     bb0: {
//         Retag([raw] _1);
//         _2 = &mut (*_1);
//         _3 = const <Test as std::ops::Drop>::drop(move _2) -> bb1;
//     }
//
//     bb1: {
//         return;
//     }
// }
// END rustc.ptr-real_drop_in_place.Test.SimplifyCfg-make_shim.after.mir
<|endoftext|>


<commit_before>use std::io::Read;

use crate::common::LineIter;

enum Dir {
    Up,
    Down,
    Forward,
}

fn parse_input(input: &mut dyn Read) -> Vec<(Dir, i32)> {
    let mut reader = LineIter::new(input);
    let mut moves = Vec::new();

    while let Some(line) = reader.next() {
        let (dir, amount) = line.split_once(" ").unwrap();

        let dir = match dir {
            "up" => Dir::Up,
            "down" => Dir::Down,
            "forward" => Dir::Forward,
            _ => panic!("Invalid direction '{}'", dir),
        };

        moves.push((dir, amount.parse().unwrap()));
    }

    moves
}

pub fn part1(input: &mut dyn Read) -> String {
    let moves = parse_input(input);

    let mut x = 0;
    let mut depth = 0;

    for (dir, amount) in moves {
        match dir {
            Dir::Up => depth -= amount,
            Dir::Down => depth += amount,
            Dir::Forward => x += amount,
        }
    }

    (x * depth).to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let moves = parse_input(input);

    let mut x = 0;
    let mut depth = 0;
    let mut aim = 0;

    for (dir, amount) in moves {
        match dir {
            Dir::Up => aim -= amount,
            Dir::Down => aim += amount,
            Dir::Forward => {
                x += amount;
                depth += aim * amount;
            }
        }
    }

    (x * depth).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/02.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 150);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part1, SAMPLE, 150);
    }
}
<commit_msg>Fix upcoming clippy warning<commit_after>use std::io::Read;

use crate::common::LineIter;

enum Dir {
    Up,
    Down,
    Forward,
}

fn parse_input(input: &mut dyn Read) -> Vec<(Dir, i32)> {
    let mut reader = LineIter::new(input);
    let mut moves = Vec::new();

    while let Some(line) = reader.next() {
        let (dir, amount) = line.split_once(' ').unwrap();

        let dir = match dir {
            "up" => Dir::Up,
            "down" => Dir::Down,
            "forward" => Dir::Forward,
            _ => panic!("Invalid direction '{}'", dir),
        };

        moves.push((dir, amount.parse().unwrap()));
    }

    moves
}

pub fn part1(input: &mut dyn Read) -> String {
    let moves = parse_input(input);

    let mut x = 0;
    let mut depth = 0;

    for (dir, amount) in moves {
        match dir {
            Dir::Up => depth -= amount,
            Dir::Down => depth += amount,
            Dir::Forward => x += amount,
        }
    }

    (x * depth).to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let moves = parse_input(input);

    let mut x = 0;
    let mut depth = 0;
    let mut aim = 0;

    for (dir, amount) in moves {
        match dir {
            Dir::Up => aim -= amount,
            Dir::Down => aim += amount,
            Dir::Forward => {
                x += amount;
                depth += aim * amount;
            }
        }
    }

    (x * depth).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = include_bytes!("samples/02.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 150);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part1, SAMPLE, 150);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::ops::Add;
use std::ops::Deref;
use std::ops::Sub;

use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::many1;
use nom::multi::separated_list1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;

use crate::common::read_input;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
struct Point3(pub [i32; 3]);

impl Point3 {
    pub fn manhattan(&self) -> i32 {
        self.0.into_iter().map(i32::abs).sum()
    }

    pub fn euler_square(&self) -> i32 {
        self.0.into_iter().map(|c| c * c).sum()
    }
}

impl Sub for Point3 {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Point3([
            self.0[0] - rhs.0[0],
            self.0[1] - rhs.0[1],
            self.0[2] - rhs.0[2],
        ])
    }
}

impl Add for Point3 {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Point3([
            self.0[0] + rhs.0[0],
            self.0[1] + rhs.0[1],
            self.0[2] + rhs.0[2],
        ])
    }
}

struct Scanner {
    visible: Vec<Point3>,
    distances: HashMap<i32, (Point3, Point3)>,
}

impl Scanner {
    pub fn new(visible: Vec<Point3>) -> Self {
        let distances = visible
            .iter()
            .enumerate()
            .flat_map(|(skip, &a)| {
                visible[(skip + 1)..]
                    .iter()
                    .map(move |&b| ((a - b).euler_square(), (a, b)))
            })
            .collect();

        Self { visible, distances }
    }

    pub fn can_overlap(&self, other: &Self) -> bool {
        other
            .distances
            .keys()
            .filter(|&k| self.distances.contains_key(k))
            .count()
            >= 11
    }
}

impl Deref for Scanner {
    type Target = [Point3];

    fn deref(&self) -> &Self::Target {
        &self.visible
    }
}

struct Rotations<'a> {
    points: &'a [Point3],
    axes: [usize; 3],
    rotation_index: usize,
}

impl<'a> Rotations<'a> {
    const ROTATIONS: [[i32; 3]; 8] = [
        [1, 1, 1],
        [1, 1, -1],
        [1, -1, 1],
        [1, -1, -1],
        [-1, 1, 1],
        [-1, 1, -1],
        [-1, -1, 1],
        [-1, -1, -1],
    ];

    pub fn new(points: &'a [Point3]) -> Self {
        Self {
            points,
            axes: [0, 1, 2],
            rotation_index: 0,
        }
    }
}

impl Iterator for Rotations<'_> {
    type Item = Vec<Point3>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rotation_index >= Self::ROTATIONS.len() {
            if !next_permutation(&mut self.axes) {
                return None;
            }

            self.rotation_index = 0;
        }

        let axes = &self.axes;
        let rot = &Self::ROTATIONS[self.rotation_index];

        let result = self
            .points
            .iter()
            .map(|Point3(coords)| {
                Point3([
                    coords[axes[0]] * rot[0],
                    coords[axes[1]] * rot[1],
                    coords[axes[2]] * rot[2],
                ])
            })
            .collect();

        self.rotation_index += 1;

        Some(result)
    }
}

fn parse_point(input: &[u8]) -> IResult<&[u8], Point3> {
    use nom::character::complete::char;
    use nom::character::complete::i32;

    map(
        tuple((i32, preceded(char(','), i32), preceded(char(','), i32))),
        |(x, y, z)| Point3([x, y, z]),
    )(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<Scanner>> {
    use nom::character::complete::i32;
    let parse_header = delimited(tag("--- scanner "), i32, tag(" ---\n"));

    let parse_scanner = map(
        preceded(parse_header, many1(terminated(parse_point, newline))),
        Scanner::new,
    );
    separated_list1(newline, parse_scanner)(input)
}

fn find_pivot(group: &Scanner, related: &Scanner) -> Option<Point3> {
    let mut counter = HashMap::new();

    for (distance, &(a, b)) in &group.distances {
        if related.distances.contains_key(distance) {
            *counter.entry(a).or_insert(0) += 1;
            *counter.entry(b).or_insert(0) += 1;
        }
    }

    counter
        .into_iter()
        .max_by_key(|(_, count)| *count)
        .map(|t| t.0)
}

fn try_overlap(matched: &Scanner, candidate: &Scanner) -> Option<(Point3, Scanner)> {
    if !matched.can_overlap(candidate) {
        return None;
    }

    let matched_pivot = find_pivot(matched, candidate)?;

    let correct: HashSet<_> = matched.iter().map(|&base| base - matched_pivot).collect();

    let mut relative = HashSet::new();
    for rot in Rotations::new(&candidate.visible) {
        for &start in &rot {
            relative.clear();

            relative.extend(rot.iter().map(|&other| other - start));

            if correct.intersection(&relative).count() >= 12 {
                // Found a solution, build the correct output
                let translated = relative
                    .drain()
                    .map(|point| point + matched_pivot)
                    .collect();

                return Some((start - matched_pivot, Scanner::new(translated)));
            }
        }
    }

    None
}

fn parts_common(input: &mut dyn Read) -> (HashSet<Point3>, Vec<Point3>) {
    let mut scanners = read_input(input, parse_input);

    let mut points: HashSet<_> = scanners[0].iter().copied().collect();

    let mut todo = vec![scanners.remove(0)];
    let mut scanners_found = vec![Point3::default()];

    while let Some(matched) = todo.pop() {
        if scanners.is_empty() {
            break;
        }

        let mut i = 0;

        while i < scanners.len() {
            if let Some((scanner, result)) = try_overlap(&matched, &scanners[i]) {
                scanners.remove(i);
                scanners_found.push(scanner);
                points.extend(result.iter().copied());
                todo.push(result);
            } else {
                i += 1;
            }
        }
    }

    (points, scanners_found)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (points, _) = parts_common(input);
    points.len().to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (_, scanners) = parts_common(input);

    scanners
        .iter()
        .flat_map(|&first| {
            scanners
                .iter()
                .map(move |&second| (first - second).manhattan())
        })
        .max()
        .unwrap()
        .to_string()
}

pub fn next_permutation<T: Ord>(list: &mut [T]) -> bool {
    // Based on: https://en.cppreference.com/w/cpp/algorithm/next_permutation
    if list.len() <= 1 {
        return false;
    }

    if let Some((i, val1)) = list
        .windows(2)
        .enumerate()
        .rev()
        .find_map(|(i, window)| (window[0] < window[1]).then(|| (i, &window[0])))
    {
        let it2 = list
            .iter()
            .enumerate()
            .skip(i + 1)
            .rev()
            .find_map(|(idx, val2)| (val1 < val2).then(|| idx))
            .expect("Unreachable, ascending pair exists");

        list.swap(i, it2);
        list[(i + 1)..].reverse();
        true
    } else {
        list.reverse();
        false
    }
}

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

    use crate::test_implementation;

    const SAMPLE: &[u8] = include_bytes!("samples/19.txt");

    #[test]
    fn test_next_permutation() {
        let mut list = [1, 2, 3];

        assert!(next_permutation(&mut list));
        assert_eq!(list, [1, 3, 2]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [2, 1, 3]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [2, 3, 1]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [3, 1, 2]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [3, 2, 1]);

        // Note the negation!
        assert!(!next_permutation(&mut list));
        assert_eq!(list, [1, 2, 3]);

        // 24 is a bit too much to write out, but we can check the number
        let mut list2 = [1, 2, 3, 4];
        for _ in 1..24 {
            assert!(next_permutation(&mut list2));
        }

        // Should be back to the start
        assert!(!next_permutation(&mut list2));
        assert_eq!(list2, [1, 2, 3, 4]);
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 79);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 3621);
    }
}
<commit_msg>Avoid instantiating translated sets<commit_after>use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::ops::Add;
use std::ops::Deref;
use std::ops::Sub;

use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::many1;
use nom::multi::separated_list1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;

use crate::common::read_input;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
struct Point3(pub [i32; 3]);

impl Point3 {
    pub fn manhattan(&self) -> i32 {
        self.0.into_iter().map(i32::abs).sum()
    }

    pub fn euler_square(&self) -> i32 {
        self.0.into_iter().map(|c| c * c).sum()
    }
}

impl Sub for Point3 {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Point3([
            self.0[0] - rhs.0[0],
            self.0[1] - rhs.0[1],
            self.0[2] - rhs.0[2],
        ])
    }
}

impl Add for Point3 {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Point3([
            self.0[0] + rhs.0[0],
            self.0[1] + rhs.0[1],
            self.0[2] + rhs.0[2],
        ])
    }
}

struct Scanner {
    visible: Vec<Point3>,
    distances: HashMap<i32, (Point3, Point3)>,
}

impl Scanner {
    pub fn new(visible: Vec<Point3>) -> Self {
        let distances = visible
            .iter()
            .enumerate()
            .flat_map(|(skip, &a)| {
                visible[(skip + 1)..]
                    .iter()
                    .map(move |&b| ((a - b).euler_square(), (a, b)))
            })
            .collect();

        Self { visible, distances }
    }

    pub fn can_overlap(&self, other: &Self) -> bool {
        other
            .distances
            .keys()
            .filter(|&k| self.distances.contains_key(k))
            .count()
            >= 11
    }
}

impl Deref for Scanner {
    type Target = [Point3];

    fn deref(&self) -> &Self::Target {
        &self.visible
    }
}

struct Rotations<'a> {
    points: &'a [Point3],
    axes: [usize; 3],
    rotation_index: usize,
}

impl<'a> Rotations<'a> {
    const ROTATIONS: [[i32; 3]; 8] = [
        [1, 1, 1],
        [1, 1, -1],
        [1, -1, 1],
        [1, -1, -1],
        [-1, 1, 1],
        [-1, 1, -1],
        [-1, -1, 1],
        [-1, -1, -1],
    ];

    pub fn new(points: &'a [Point3]) -> Self {
        Self {
            points,
            axes: [0, 1, 2],
            rotation_index: 0,
        }
    }
}

impl Iterator for Rotations<'_> {
    type Item = Vec<Point3>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.rotation_index >= Self::ROTATIONS.len() {
            if !next_permutation(&mut self.axes) {
                return None;
            }

            self.rotation_index = 0;
        }

        let axes = &self.axes;
        let rot = &Self::ROTATIONS[self.rotation_index];

        let result = self
            .points
            .iter()
            .map(|Point3(coords)| {
                Point3([
                    coords[axes[0]] * rot[0],
                    coords[axes[1]] * rot[1],
                    coords[axes[2]] * rot[2],
                ])
            })
            .collect();

        self.rotation_index += 1;

        Some(result)
    }
}

fn parse_point(input: &[u8]) -> IResult<&[u8], Point3> {
    use nom::character::complete::char;
    use nom::character::complete::i32;

    map(
        tuple((i32, preceded(char(','), i32), preceded(char(','), i32))),
        |(x, y, z)| Point3([x, y, z]),
    )(input)
}

fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<Scanner>> {
    use nom::character::complete::i32;
    let parse_header = delimited(tag("--- scanner "), i32, tag(" ---\n"));

    let parse_scanner = map(
        preceded(parse_header, many1(terminated(parse_point, newline))),
        Scanner::new,
    );
    separated_list1(newline, parse_scanner)(input)
}

fn find_pivot(group: &Scanner, related: &Scanner) -> Option<Point3> {
    let mut counter = HashMap::new();

    for (distance, &(a, b)) in &group.distances {
        if related.distances.contains_key(distance) {
            *counter.entry(a).or_insert(0) += 1;
            *counter.entry(b).or_insert(0) += 1;
        }
    }

    counter
        .into_iter()
        .max_by_key(|(_, count)| *count)
        .map(|t| t.0)
}

fn try_overlap(matched: &Scanner, candidate: &Scanner) -> Option<(Point3, Scanner)> {
    if !matched.can_overlap(candidate) {
        return None;
    }

    let matched_pivot = find_pivot(matched, candidate)?;

    let correct: HashSet<_> = matched.iter().map(|&base| base - matched_pivot).collect();

    for rot in Rotations::new(candidate) {
        for &start in &rot {
            let translated_iter = rot.iter().map(|&other| other - start);

            if translated_iter
                .clone()
                .filter(|p| correct.contains(p))
                .count()
                >= 12
            {
                // Found a solution, build the correct output
                let translated = translated_iter.map(|point| point + matched_pivot).collect();

                return Some((start - matched_pivot, Scanner::new(translated)));
            }
        }
    }

    None
}

fn parts_common(input: &mut dyn Read) -> (HashSet<Point3>, Vec<Point3>) {
    let mut scanners = read_input(input, parse_input);

    let mut points: HashSet<_> = scanners[0].iter().copied().collect();

    let mut todo = vec![scanners.remove(0)];
    let mut scanners_found = vec![Point3::default()];

    while let Some(matched) = todo.pop() {
        if scanners.is_empty() {
            break;
        }

        let mut i = 0;

        while i < scanners.len() {
            if let Some((scanner, result)) = try_overlap(&matched, &scanners[i]) {
                scanners.remove(i);
                scanners_found.push(scanner);
                points.extend(result.iter().copied());
                todo.push(result);
            } else {
                i += 1;
            }
        }
    }

    assert!(scanners.is_empty());

    (points, scanners_found)
}

pub fn part1(input: &mut dyn Read) -> String {
    let (points, _) = parts_common(input);
    points.len().to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let (_, scanners) = parts_common(input);

    scanners
        .iter()
        .flat_map(|&first| {
            scanners
                .iter()
                .map(move |&second| (first - second).manhattan())
        })
        .max()
        .unwrap()
        .to_string()
}

pub fn next_permutation<T: Ord>(list: &mut [T]) -> bool {
    // Based on: https://en.cppreference.com/w/cpp/algorithm/next_permutation
    if list.len() <= 1 {
        return false;
    }

    if let Some((i, val1)) = list
        .windows(2)
        .enumerate()
        .rev()
        .find_map(|(i, window)| (window[0] < window[1]).then(|| (i, &window[0])))
    {
        let it2 = list
            .iter()
            .enumerate()
            .skip(i + 1)
            .rev()
            .find_map(|(idx, val2)| (val1 < val2).then(|| idx))
            .expect("Unreachable, ascending pair exists");

        list.swap(i, it2);
        list[(i + 1)..].reverse();
        true
    } else {
        list.reverse();
        false
    }
}

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

    use crate::test_implementation;

    const SAMPLE: &[u8] = include_bytes!("samples/19.txt");

    #[test]
    fn test_next_permutation() {
        let mut list = [1, 2, 3];

        assert!(next_permutation(&mut list));
        assert_eq!(list, [1, 3, 2]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [2, 1, 3]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [2, 3, 1]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [3, 1, 2]);

        assert!(next_permutation(&mut list));
        assert_eq!(list, [3, 2, 1]);

        // Note the negation!
        assert!(!next_permutation(&mut list));
        assert_eq!(list, [1, 2, 3]);

        // 24 is a bit too much to write out, but we can check the number
        let mut list2 = [1, 2, 3, 4];
        for _ in 1..24 {
            assert!(next_permutation(&mut list2));
        }

        // Should be back to the start
        assert!(!next_permutation(&mut list2));
        assert_eq!(list2, [1, 2, 3, 4]);
    }

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 79);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 3621);
    }
}
<|endoftext|>