<commit_before>// REFERENCE:
// https://adamschoenemann.dk/posts/2018-05-29-pattern-matching.html

#[cfg(test)]
mod tests;

use crate::{supply::Supply, typechecker::env::EnvConstructors};
use ditto_ast::{
    self as ast, FullyQualifiedProperName, ProperName, QualifiedProperName, Span, Type,
};
use std::collections::HashMap;

pub fn is_exhaustive(
    env_constructors: &EnvConstructors,
    pattern_type: Type,
    patterns: Vec<ast::Pattern>,
) -> Option<Error> {
    let mut supply = Supply(0);
    let mut env = Env::new();
    let fresh_name = supply.fresh();
    let constructors = constructors_for_type(&pattern_type, env_constructors);
    env.insert(fresh_name, constructors);
    let ideal = IdealPattern::Variable { var: fresh_name };
    let clause_patterns = patterns.into_iter().map(ClausePattern::from).collect();
    let result = check_coverage(&env, env_constructors, &mut supply, &ideal, clause_patterns);
    result.err()
}

type Name = String;
type FreshName = usize;

#[derive(Debug, Clone)]
pub enum ClausePattern {
    Constructor {
        span: Span,
        constructor: ProperName,
        arguments: Vec<Self>,
    },
    Variable {
        span: Span,
        var: Name,
    },
}
type ClausePatterns = Vec<ClausePattern>;

impl ClausePattern {
    pub fn get_span(&self) -> Span {
        match self {
            Self::Constructor { span, .. } => *span,
            Self::Variable { span, .. } => *span,
        }
    }
}

impl std::convert::From<ast::Pattern> for ClausePattern {
    fn from(ast_pattern: ast::Pattern) -> Self {
        match ast_pattern {
            ast::Pattern::LocalConstructor {
                span,
                constructor,
                arguments,
            } => Self::Constructor {
                span,
                constructor,
                arguments: arguments.into_iter().map(Self::from).collect(),
            },
            ast::Pattern::ImportedConstructor {
                span,
                constructor,
                arguments,
            } => Self::Constructor {
                span,
                constructor: constructor.value,
                arguments: arguments.into_iter().map(Self::from).collect(),
            },
            ast::Pattern::Variable { name, span } => Self::Variable { span, var: name.0 },
            ast::Pattern::Unused { unused_name, span } => Self::Variable {
                span,
                var: unused_name.0,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub enum IdealPattern {
    Constructor {
        constructor: ProperName,
        arguments: Vec<Self>,
    },
    Variable {
        var: FreshName,
    },
}
type IdealPatterns = Vec<IdealPattern>;

impl IdealPattern {
    fn from_clause(clause_pattern: &ClausePattern, supply: &mut Supply) -> Self {
        match clause_pattern {
            ClausePattern::Constructor {
                constructor,
                arguments,
                ..
            } => Self::Constructor {
                constructor: constructor.clone(),
                arguments: arguments
                    .iter()
                    .map(|arg| IdealPattern::from_clause(arg, supply))
                    .collect(),
            },
            ClausePattern::Variable { .. } => Self::Variable {
                var: supply.fresh(),
            },
        }
    }

    pub fn render(&self) -> String {
        let mut accum = String::new();
        self.render_rec(&mut accum);
        accum
    }

    fn render_rec(&self, accum: &mut String) {
        match self {
            Self::Constructor {
                constructor,
                arguments,
            } => {
                accum.push_str(&constructor.0);
                let arg_len = arguments.len();
                if arg_len > 0 {
                    accum.push('(');
                    for (i, arg) in arguments.iter().enumerate() {
                        arg.render_rec(accum);
                        if i < arg_len - 1 {
                            accum.push_str(", ");
                        }
                    }
                    accum.push(')');
                }
            }
            Self::Variable { .. } => {
                //accum.push_str(&format!("_{}", var));
                accum.push('_')
            }
        }
    }
}

#[derive(Debug, Clone)]
struct Clause {
    usages: usize,
    pattern: ClausePattern,
}

impl Clause {
    fn new(pattern: ClausePattern) -> Self {
        Self { usages: 0, pattern }
    }

    fn use_clause(&self) -> Self {
        Self {
            usages: self.usages + 1,
            pattern: self.pattern.clone(),
        }
    }
}

type Result<T = ()> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    RedundantClauses(ClausePatterns),
    NotCovered(IdealPatterns),
    // These shouldn't happen if the patterns are well-typed,
    // but it's up to the caller to handle them as `unreachable!` (or not)
    MalformedPattern {
        ideal_arg_len: usize,
        clause_arg_len: usize,
        malformed_pattern: ClausePattern,
    },
}

type Env = HashMap<FreshName, Constructors>;

#[derive(Debug, Clone)]
pub struct Constructor {
    name: QualifiedProperName,
    arguments: Vec<Type>,
}
type Constructors = Vec<Constructor>;

impl Constructor {
    /// Given the Constructor `Just [Just [Int]]`
    /// returns the ideal pattern `Just(_)`
    /// and an Env where `_` maps to the constructors `Just [Int]` and `Nothing []`
    fn to_pattern(
        &self,
        supply: &mut Supply,
        env_constructors: &EnvConstructors,
    ) -> (IdealPattern, Env) {
        let mut env = Env::new();
        let mut pattern_arguments = Vec::new();
        for arg in self.arguments.iter() {
            let fresh_name = supply.fresh();
            let constructors = constructors_for_type(arg, env_constructors);
            env.insert(fresh_name, constructors);
            pattern_arguments.push(IdealPattern::Variable { var: fresh_name });
        }
        (
            IdealPattern::Constructor {
                constructor: self.name.value.clone(),
                arguments: pattern_arguments,
            },
            env,
        )
    }
}

fn constructors_for_type(pattern_type: &Type, env_constructors: &EnvConstructors) -> Constructors {
    match pattern_type {
        Type::Call {
            function:
                box Type::Constructor {
                    canonical_value: want_canonical_value,
                    ..
                },
            arguments: specific_arguments,
        } => {
            return env_constructors
                .iter()
                .filter_map(|(name, ctor)| {
                    // NOTE: we're deliberately not instantiating the scheme
                    // as there's no need here
                    let constructor_type = ctor.get_scheme().signature;

                    if want_canonical_value == get_canonical_value(&constructor_type) {
                        let mut constructor_arguments = get_function_parameters(&constructor_type);
                        if let Some(Type::Call {
                            arguments: generic_arguments,
                            ..
                        }) = get_function_return_type(&constructor_type)
                        {
                            let type_subst: HashMap<Type, Type> = generic_arguments
                                .into_iter()
                                .zip(specific_arguments.clone())
                                .collect();
                            constructor_arguments = constructor_arguments
                                .into_iter()
                                .map(|arg| {
                                    if let Some(t) = type_subst.get(&arg).cloned() {
                                        t
                                    } else {
                                        arg
                                    }
                                })
                                .collect();
                        }
                        Some(Constructor {
                            name: name.clone(),
                            arguments: constructor_arguments,
                        })
                    } else {
                        None
                    }
                })
                .collect();
        }

        Type::Constructor {
            canonical_value: want_canonical_value,
            ..
        } => {
            return env_constructors
                .iter()
                .filter_map(|(name, ctor)| {
                    // NOTE: we're deliberately not instantiating the scheme
                    // as there's no need here
                    let constructor_type = ctor.get_scheme().signature;

                    if want_canonical_value == get_canonical_value(&constructor_type) {
                        Some(Constructor {
                            name: name.clone(),
                            arguments: get_function_parameters(&constructor_type),
                        })
                    } else {
                        None
                    }
                })
                .collect();
        }
        _ => return Vec::new(),
    }

    fn get_canonical_value(constructor_type: &Type) -> &FullyQualifiedProperName {
        match constructor_type {
            Type::Constructor {
                canonical_value, ..
            } => canonical_value,
            Type::Call { function, .. } => get_canonical_value(function),
            Type::Function { return_type, .. } => get_canonical_value(return_type),
            other => unreachable!("{:?}", other),
        }
    }

    fn get_function_parameters(constructor_type: &Type) -> Vec<Type> {
        match constructor_type {
            Type::Function { parameters, .. } => parameters.clone(),
            _ => Vec::new(),
        }
    }
    fn get_function_return_type(constructor_type: &Type) -> Option<Type> {
        match constructor_type {
            Type::Function {
                box return_type, ..
            } => Some(return_type.clone()),
            _ => None,
        }
    }
}

fn check_coverage(
    env: &Env,
    env_constructors: &EnvConstructors,
    supply: &mut Supply,
    ideal: &IdealPattern,
    clause_patterns: ClausePatterns,
) -> Result {
    let clauses = clause_patterns
        .into_iter()
        .map(Clause::new)
        .collect::<Vec<_>>();

    let mut not_covered = IdealPatterns::new();
    let checked_clauses = covered_by(
        env,
        env_constructors,
        supply,
        ideal,
        &clauses,
        &mut not_covered,
    )?;

    if !not_covered.is_empty() {
        return Err(Error::NotCovered(not_covered));
    }

    let unused_patterns: ClausePatterns = checked_clauses
        .into_iter()
        .filter_map(|clause| {
            if clause.usages < 1 {
                Some(clause.pattern)
            } else {
                None
            }
        })
        .collect();

    if unused_patterns.is_empty() {
        Ok(())
    } else {
        Err(Error::RedundantClauses(unused_patterns))
    }
}

fn covered_by(
    env: &Env,
    env_constructors: &EnvConstructors,
    supply: &mut Supply,
    ideal: &IdealPattern,
    clauses: &[Clause],
    not_covered: &mut IdealPatterns,
) -> Result<Vec<Clause>> {
    use IsInjectiveResult::*;

    if let Some((clause, remaining_clauses)) = clauses.split_first() {
        if let Some(subst) = has_subst(supply, ideal, &clause.pattern)? {
            match is_injective(subst) {
                Injective => {
                    let mut checked_clauses = vec![clause.use_clause()];
                    checked_clauses.extend(remaining_clauses.to_vec());
                    Ok(checked_clauses)
                }
                NotInjective(fresh_name) => {
                    let constructors = env.get(&fresh_name).unwrap();
                    constructors
                        .iter()
                        .fold(Ok(clauses.to_vec()), |result, constructor| {
                            let clauses = result?;
                            let (new_ideal, new_env) =
                                constructor.to_pattern(supply, env_constructors);
                            let new_subst = singleton_subst(fresh_name, new_ideal);
                            let new_ideal = apply(&new_subst, ideal);
                            let mut env = env.clone();
                            env.extend(new_env);
                            covered_by(
                                &env,
                                env_constructors,
                                supply,
                                &new_ideal,
                                &clauses,
                                not_covered,
                            )
                        })
                }
            }
        } else {
            let mut checked_clauses = vec![clause.clone()];
            checked_clauses.extend(covered_by(
                env,
                env_constructors,
                supply,
                ideal,
                remaining_clauses,
                not_covered,
            )?);
            Ok(checked_clauses)
        }
    } else {
        not_covered.push(ideal.clone());
        Ok(clauses.to_vec())
    }
}

type Subst = HashMap<FreshName, IdealPattern>;

fn singleton_subst(fresh_name: FreshName, ideal_pattern: IdealPattern) -> Subst {
    Subst::from([(fresh_name, ideal_pattern)])
}

fn has_subst(
    supply: &mut Supply,
    ideal: &IdealPattern,
    clause_pattern: &ClausePattern,
) -> Result<Option<Subst>> {
    match (ideal, clause_pattern) {
        (IdealPattern::Variable { var: fresh_name }, clause_pattern) => {
            let subst = singleton_subst(
                *fresh_name,
                IdealPattern::from_clause(clause_pattern, supply),
            );
            Ok(Some(subst))
        }
        (
            IdealPattern::Constructor {
                constructor: ideal_constructor,
                arguments: ideal_arguments,
            },
            ClausePattern::Constructor {
                constructor: clause_constructor,
                arguments: clause_arguments,
                ..
            },
        ) => {
            if ideal_constructor != clause_constructor {
                return Ok(None);
            }
            if ideal_arguments.len() != clause_arguments.len() {
                return Err(Error::MalformedPattern {
                    ideal_arg_len: ideal_arguments.len(),
                    clause_arg_len: clause_arguments.len(),
                    malformed_pattern: clause_pattern.clone(),
                });
            }
            let mut subst = Subst::new();
            if ideal_arguments.is_empty() {
                return Ok(Some(subst));
            }
            for (ideal_argument, clause_argument) in ideal_arguments.iter().zip(clause_arguments) {
                if let Some(arg_subst) = has_subst(supply, ideal_argument, clause_argument)? {
                    subst.extend(arg_subst)
                } else {
                    return Ok(None);
                }
            }
            Ok(Some(subst))
        }
        (IdealPattern::Constructor { .. }, ClausePattern::Variable { .. }) => {
            Ok(Some(Subst::new()))
        }
    }
}

enum IsInjectiveResult {
    Injective,
    NotInjective(FreshName),
}

// A substitution is injective (i.e. one-to-one) if it contains _only_ pattern variables.
fn is_injective(subst: Subst) -> IsInjectiveResult {
    use IsInjectiveResult::*;
    for (var, pattern) in subst {
        if matches!(pattern, IdealPattern::Constructor { .. }) {
            return NotInjective(var);
        }
    }
    Injective
}

fn apply(subst: &Subst, ideal: &IdealPattern) -> IdealPattern {
    match ideal {
        IdealPattern::Variable { var } => subst.get(var).map_or_else(
            || IdealPattern::Variable { var: *var },
            |pattern| apply(subst, pattern),
            //        ^^ I'm assuming we need to recursively substitute here?
        ),
        IdealPattern::Constructor {
            constructor,
            arguments,
        } => IdealPattern::Constructor {
            constructor: constructor.clone(),
            arguments: arguments.iter().map(|arg| apply(subst, arg)).collect(),
        },
    }
}
<commit_msg>Missing patterns error should include only unique patterns<commit_after>// REFERENCE:
// https://adamschoenemann.dk/posts/2018-05-29-pattern-matching.html

#[cfg(test)]
mod tests;

use crate::{supply::Supply, typechecker::env::EnvConstructors};
use ditto_ast::{
    self as ast, FullyQualifiedProperName, ProperName, QualifiedProperName, Span, Type,
};
use std::collections::{HashMap, HashSet};

pub fn is_exhaustive(
    env_constructors: &EnvConstructors,
    pattern_type: Type,
    patterns: Vec<ast::Pattern>,
) -> Option<Error> {
    let mut supply = Supply(0);
    let mut env = Env::new();
    let fresh_name = supply.fresh();
    let constructors = constructors_for_type(&pattern_type, env_constructors);
    env.insert(fresh_name, constructors);
    let ideal = IdealPattern::Variable { var: fresh_name };
    let clause_patterns = patterns.into_iter().map(ClausePattern::from).collect();
    let result = check_coverage(&env, env_constructors, &mut supply, &ideal, clause_patterns);
    result.err()
}

type Name = String;
type FreshName = usize;

#[derive(Debug, Clone)]
pub enum ClausePattern {
    Constructor {
        span: Span,
        constructor: ProperName,
        arguments: Vec<Self>,
    },
    Variable {
        span: Span,
        var: Name,
    },
}
type ClausePatterns = Vec<ClausePattern>;

impl ClausePattern {
    pub fn get_span(&self) -> Span {
        match self {
            Self::Constructor { span, .. } => *span,
            Self::Variable { span, .. } => *span,
        }
    }
}

impl std::convert::From<ast::Pattern> for ClausePattern {
    fn from(ast_pattern: ast::Pattern) -> Self {
        match ast_pattern {
            ast::Pattern::LocalConstructor {
                span,
                constructor,
                arguments,
            } => Self::Constructor {
                span,
                constructor,
                arguments: arguments.into_iter().map(Self::from).collect(),
            },
            ast::Pattern::ImportedConstructor {
                span,
                constructor,
                arguments,
            } => Self::Constructor {
                span,
                constructor: constructor.value,
                arguments: arguments.into_iter().map(Self::from).collect(),
            },
            ast::Pattern::Variable { name, span } => Self::Variable { span, var: name.0 },
            ast::Pattern::Unused { unused_name, span } => Self::Variable {
                span,
                var: unused_name.0,
            },
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum IdealPattern<Var = FreshName> {
    Constructor {
        constructor: ProperName,
        arguments: Vec<Self>,
    },
    Variable {
        var: Var,
    },
}

impl IdealPattern {
    fn from_clause(clause_pattern: &ClausePattern, supply: &mut Supply) -> Self {
        match clause_pattern {
            ClausePattern::Constructor {
                constructor,
                arguments,
                ..
            } => Self::Constructor {
                constructor: constructor.clone(),
                arguments: arguments
                    .iter()
                    .map(|arg| IdealPattern::from_clause(arg, supply))
                    .collect(),
            },
            ClausePattern::Variable { .. } => Self::Variable {
                var: supply.fresh(),
            },
        }
    }

    fn void(&self) -> IdealPattern<()> {
        match self {
            Self::Constructor {
                constructor,
                arguments,
            } => IdealPattern::Constructor {
                constructor: constructor.clone(),
                arguments: arguments.iter().map(|arg| arg.void()).collect(),
            },
            Self::Variable { .. } => IdealPattern::Variable { var: () },
        }
    }
}
impl IdealPattern<()> {
    pub fn render(&self) -> String {
        let mut accum = String::new();
        self.render_rec(&mut accum);
        accum
    }

    fn render_rec(&self, accum: &mut String) {
        match self {
            Self::Constructor {
                constructor,
                arguments,
            } => {
                accum.push_str(&constructor.0);
                let arg_len = arguments.len();
                if arg_len > 0 {
                    accum.push('(');
                    for (i, arg) in arguments.iter().enumerate() {
                        arg.render_rec(accum);
                        if i < arg_len - 1 {
                            accum.push_str(", ");
                        }
                    }
                    accum.push(')');
                }
            }
            Self::Variable { .. } => {
                //accum.push_str(&format!("_{}", var));
                accum.push('_')
            }
        }
    }
}

#[derive(Debug, Clone)]
struct Clause {
    usages: usize,
    pattern: ClausePattern,
}

impl Clause {
    fn new(pattern: ClausePattern) -> Self {
        Self { usages: 0, pattern }
    }

    fn use_clause(&self) -> Self {
        Self {
            usages: self.usages + 1,
            pattern: self.pattern.clone(),
        }
    }
}

type Result<T = ()> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    RedundantClauses(ClausePatterns),
    NotCovered(NotCovered),
    // These shouldn't happen if the patterns are well-typed,
    // but it's up to the caller to handle them as `unreachable!` (or not)
    MalformedPattern {
        ideal_arg_len: usize,
        clause_arg_len: usize,
        malformed_pattern: ClausePattern,
    },
}

type NotCovered = HashSet<IdealPattern<()>>;

type Env = HashMap<FreshName, Constructors>;

#[derive(Debug, Clone)]
pub struct Constructor {
    name: QualifiedProperName,
    arguments: Vec<Type>,
}
type Constructors = Vec<Constructor>;

impl Constructor {
    /// Given the Constructor `Just [Just [Int]]`
    /// returns the ideal pattern `Just(_)`
    /// and an Env where `_` maps to the constructors `Just [Int]` and `Nothing []`
    fn to_pattern(
        &self,
        supply: &mut Supply,
        env_constructors: &EnvConstructors,
    ) -> (IdealPattern, Env) {
        let mut env = Env::new();
        let mut pattern_arguments = Vec::new();
        for arg in self.arguments.iter() {
            let fresh_name = supply.fresh();
            let constructors = constructors_for_type(arg, env_constructors);
            env.insert(fresh_name, constructors);
            pattern_arguments.push(IdealPattern::Variable { var: fresh_name });
        }
        (
            IdealPattern::Constructor {
                constructor: self.name.value.clone(),
                arguments: pattern_arguments,
            },
            env,
        )
    }
}

fn constructors_for_type(pattern_type: &Type, env_constructors: &EnvConstructors) -> Constructors {
    match pattern_type {
        Type::Call {
            function:
                box Type::Constructor {
                    canonical_value: want_canonical_value,
                    ..
                },
            arguments: specific_arguments,
        } => {
            return env_constructors
                .iter()
                .filter_map(|(name, ctor)| {
                    // NOTE: we're deliberately not instantiating the scheme
                    // as there's no need here
                    let constructor_type = ctor.get_scheme().signature;

                    if want_canonical_value == get_canonical_value(&constructor_type) {
                        let mut constructor_arguments = get_function_parameters(&constructor_type);
                        if let Some(Type::Call {
                            arguments: generic_arguments,
                            ..
                        }) = get_function_return_type(&constructor_type)
                        {
                            let type_subst: HashMap<Type, Type> = generic_arguments
                                .into_iter()
                                .zip(specific_arguments.clone())
                                .collect();
                            constructor_arguments = constructor_arguments
                                .into_iter()
                                .map(|arg| {
                                    if let Some(t) = type_subst.get(&arg).cloned() {
                                        t
                                    } else {
                                        arg
                                    }
                                })
                                .collect();
                        }
                        Some(Constructor {
                            name: name.clone(),
                            arguments: constructor_arguments,
                        })
                    } else {
                        None
                    }
                })
                .collect();
        }

        Type::Constructor {
            canonical_value: want_canonical_value,
            ..
        } => {
            return env_constructors
                .iter()
                .filter_map(|(name, ctor)| {
                    // NOTE: we're deliberately not instantiating the scheme
                    // as there's no need here
                    let constructor_type = ctor.get_scheme().signature;

                    if want_canonical_value == get_canonical_value(&constructor_type) {
                        Some(Constructor {
                            name: name.clone(),
                            arguments: get_function_parameters(&constructor_type),
                        })
                    } else {
                        None
                    }
                })
                .collect();
        }
        _ => return Vec::new(),
    }

    fn get_canonical_value(constructor_type: &Type) -> &FullyQualifiedProperName {
        match constructor_type {
            Type::Constructor {
                canonical_value, ..
            } => canonical_value,
            Type::Call { function, .. } => get_canonical_value(function),
            Type::Function { return_type, .. } => get_canonical_value(return_type),
            other => unreachable!("{:?}", other),
        }
    }

    fn get_function_parameters(constructor_type: &Type) -> Vec<Type> {
        match constructor_type {
            Type::Function { parameters, .. } => parameters.clone(),
            _ => Vec::new(),
        }
    }
    fn get_function_return_type(constructor_type: &Type) -> Option<Type> {
        match constructor_type {
            Type::Function {
                box return_type, ..
            } => Some(return_type.clone()),
            _ => None,
        }
    }
}

fn check_coverage(
    env: &Env,
    env_constructors: &EnvConstructors,
    supply: &mut Supply,
    ideal: &IdealPattern,
    clause_patterns: ClausePatterns,
) -> Result {
    let clauses = clause_patterns
        .into_iter()
        .map(Clause::new)
        .collect::<Vec<_>>();

    let mut not_covered = NotCovered::new();
    let checked_clauses = covered_by(
        env,
        env_constructors,
        supply,
        ideal,
        &clauses,
        &mut not_covered,
    )?;

    if !not_covered.is_empty() {
        return Err(Error::NotCovered(not_covered));
    }

    let unused_patterns: ClausePatterns = checked_clauses
        .into_iter()
        .filter_map(|clause| {
            if clause.usages < 1 {
                Some(clause.pattern)
            } else {
                None
            }
        })
        .collect();

    if unused_patterns.is_empty() {
        Ok(())
    } else {
        Err(Error::RedundantClauses(unused_patterns))
    }
}

fn covered_by(
    env: &Env,
    env_constructors: &EnvConstructors,
    supply: &mut Supply,
    ideal: &IdealPattern,
    clauses: &[Clause],
    not_covered: &mut NotCovered,
) -> Result<Vec<Clause>> {
    use IsInjectiveResult::*;

    if let Some((clause, remaining_clauses)) = clauses.split_first() {
        if let Some(subst) = has_subst(supply, ideal, &clause.pattern)? {
            match is_injective(subst) {
                Injective => {
                    let mut checked_clauses = vec![clause.use_clause()];
                    checked_clauses.extend(remaining_clauses.to_vec());
                    Ok(checked_clauses)
                }
                NotInjective(fresh_name) => {
                    let constructors = env.get(&fresh_name).unwrap();
                    constructors
                        .iter()
                        .fold(Ok(clauses.to_vec()), |result, constructor| {
                            let clauses = result?;
                            let (new_ideal, new_env) =
                                constructor.to_pattern(supply, env_constructors);
                            let new_subst = singleton_subst(fresh_name, new_ideal);
                            let new_ideal = apply(&new_subst, ideal);
                            let mut env = env.clone();
                            env.extend(new_env);
                            covered_by(
                                &env,
                                env_constructors,
                                supply,
                                &new_ideal,
                                &clauses,
                                not_covered,
                            )
                        })
                }
            }
        } else {
            let mut checked_clauses = vec![clause.clone()];
            checked_clauses.extend(covered_by(
                env,
                env_constructors,
                supply,
                ideal,
                remaining_clauses,
                not_covered,
            )?);
            Ok(checked_clauses)
        }
    } else {
        not_covered.insert(ideal.void());
        Ok(clauses.to_vec())
    }
}

type Subst = HashMap<FreshName, IdealPattern>;

fn singleton_subst(fresh_name: FreshName, ideal_pattern: IdealPattern) -> Subst {
    Subst::from([(fresh_name, ideal_pattern)])
}

fn has_subst(
    supply: &mut Supply,
    ideal: &IdealPattern,
    clause_pattern: &ClausePattern,
) -> Result<Option<Subst>> {
    match (ideal, clause_pattern) {
        (IdealPattern::Variable { var: fresh_name }, clause_pattern) => {
            let subst = singleton_subst(
                *fresh_name,
                IdealPattern::from_clause(clause_pattern, supply),
            );
            Ok(Some(subst))
        }
        (
            IdealPattern::Constructor {
                constructor: ideal_constructor,
                arguments: ideal_arguments,
            },
            ClausePattern::Constructor {
                constructor: clause_constructor,
                arguments: clause_arguments,
                ..
            },
        ) => {
            if ideal_constructor != clause_constructor {
                return Ok(None);
            }
            if ideal_arguments.len() != clause_arguments.len() {
                return Err(Error::MalformedPattern {
                    ideal_arg_len: ideal_arguments.len(),
                    clause_arg_len: clause_arguments.len(),
                    malformed_pattern: clause_pattern.clone(),
                });
            }
            let mut subst = Subst::new();
            if ideal_arguments.is_empty() {
                return Ok(Some(subst));
            }
            for (ideal_argument, clause_argument) in ideal_arguments.iter().zip(clause_arguments) {
                if let Some(arg_subst) = has_subst(supply, ideal_argument, clause_argument)? {
                    subst.extend(arg_subst)
                } else {
                    return Ok(None);
                }
            }
            Ok(Some(subst))
        }
        (IdealPattern::Constructor { .. }, ClausePattern::Variable { .. }) => {
            Ok(Some(Subst::new()))
        }
    }
}

enum IsInjectiveResult {
    Injective,
    NotInjective(FreshName),
}

// A substitution is injective (i.e. one-to-one) if it contains _only_ pattern variables.
fn is_injective(subst: Subst) -> IsInjectiveResult {
    use IsInjectiveResult::*;
    for (var, pattern) in subst {
        if matches!(pattern, IdealPattern::Constructor { .. }) {
            return NotInjective(var);
        }
    }
    Injective
}

fn apply(subst: &Subst, ideal: &IdealPattern) -> IdealPattern {
    match ideal {
        IdealPattern::Variable { var } => subst.get(var).map_or_else(
            || IdealPattern::Variable { var: *var },
            |pattern| apply(subst, pattern),
            //        ^^ I'm assuming we need to recursively substitute here?
        ),
        IdealPattern::Constructor {
            constructor,
            arguments,
        } => IdealPattern::Constructor {
            constructor: constructor.clone(),
            arguments: arguments.iter().map(|arg| apply(subst, arg)).collect(),
        },
    }
}
<|endoftext|>


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

//! Utilities for detecting and working with indentation.

extern crate xi_rope;

use std::collections::BTreeMap;
use xi_rope::Rope;

/// An enumeration of legal indentation types.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Indentation {
    Tabs,
    Spaces(usize),
}

/// A struct representing the mixed indentation error.
#[derive(Debug)]
pub struct MixedIndentError;

impl Indentation {
    /// Parses a rope for indentation settings.
    pub fn parse(rope: &Rope) -> Result<Option<Self>, MixedIndentError> {
        let lines = rope.lines_raw(..);
        let mut tabs = false;
        let mut spaces: BTreeMap<usize, usize> = BTreeMap::new();

        for line in lines {
            match Indentation::parse_line(&line) {
                Ok(Some(Indentation::Spaces(size))) => {
                    let counter = spaces.entry(size).or_insert(0);
                    *counter += 1;
                }
                Ok(Some(Indentation::Tabs)) => tabs = true,
                Ok(None) => continue,
                Err(e) => return Err(e),
            }
        }

        match (tabs, !spaces.is_empty()) {
            (true, true) => Err(MixedIndentError),
            (true, false) => Ok(Some(Indentation::Tabs)),
            (false, true) => Ok(Some(Indentation::Spaces(extract_count(spaces)))),
            _ => Ok(None),
        }
    }

    /// Detects the indentation on a specific line.
    /// Parses whitespace until first occurrence of something else
    pub fn parse_line(line: &str) -> Result<Option<Self>, MixedIndentError> {
        let mut spaces = 0;

        for char in line.as_bytes() {
            match char {
                b' ' => spaces += 1,
                b'\t' if spaces > 0 => return Err(MixedIndentError),
                b'\t' => return Ok(Some(Indentation::Tabs)),
                _ => break,
            }
        }

        if spaces > 0 {
            Ok(Some(Indentation::Spaces(spaces)))
        } else {
            Ok(None)
        }
    }
}

/// Uses a heuristic to calculate the greatest common denominator of most used indentation depths.
///
/// As BTreeMaps are ordered by value, using take on the iterator ensures the indentation levels
/// most frequently used in the file are extracted.
fn extract_count(spaces: BTreeMap<usize, usize>) -> usize {
    let mut take_size = 4;

    if spaces.len() < take_size {
        take_size = spaces.len();
    }

    // Fold results using GCD, skipping numbers which result in gcd returning 1
    spaces.iter().take(take_size).fold(0, |a, (b, _)| {
        let d = gcd(a, *b);
        if d == 1 {
            a
        } else {
            d
        }
    })
}

/// Simple implementation to calculate greatest common divisor, based on Euclid's algorithm
fn gcd(a: usize, b: usize) -> usize {
    if a == 0 {
        b
    } else if b == 0 || a == b {
        a
    } else {
        let mut a = a;
        let mut b = b;

        while b > 0 {
            let r = a % b;
            a = b;
            b = r;
        }
        a
    }
}

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

    #[test]
    fn gcd_calculates_correctly() {
        assert_eq!(21, gcd(1071, 462));
        assert_eq!(6, gcd(270, 192));
    }

    #[test]
    fn line_gets_two_spaces() {
        let result = Indentation::parse_line("  ");
        let expected = Indentation::Spaces(2);

        assert_eq!(result.unwrap(), Some(expected));
    }

    #[test]
    fn line_gets_tabs() {
        let result = Indentation::parse_line("\t");
        let expected = Indentation::Tabs;

        assert_eq!(result.unwrap(), Some(expected));
    }

    #[test]
    fn line_errors_mixed_indent() {
        let result = Indentation::parse_line("  \t");
        assert!(result.is_err());
    }

    #[test]
    fn rope_gets_two_spaces() {
        let result = Indentation::parse(&Rope::from(
            r#"
        // This is a comment
          Testing
          Indented
            Even more indented
            # Comment
            # Comment
            # Comment
        "#,
        ));
        let expected = Indentation::Spaces(2);

        assert_eq!(result.unwrap(), Some(expected));
    }

    #[test]
    fn rope_gets_four_spaces() {
        let result = Indentation::parse(&Rope::from(
            r#"
        fn my_fun_func(&self,
                       another_arg: usize) -> Fun {
            /* Random comment describing program behavior */
            Fun::from(another_arg)
        }
        "#,
        ));
        let expected = Indentation::Spaces(4);

        assert_eq!(result.unwrap(), Some(expected));
    }
}
<commit_msg>Bugfix: return None when detected tab_size in file is 0<commit_after>// Copyright 2018 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Utilities for detecting and working with indentation.

extern crate xi_rope;

use std::collections::BTreeMap;
use xi_rope::Rope;

/// An enumeration of legal indentation types.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Indentation {
    Tabs,
    Spaces(usize),
}

/// A struct representing the mixed indentation error.
#[derive(Debug)]
pub struct MixedIndentError;

impl Indentation {
    /// Parses a rope for indentation settings.
    pub fn parse(rope: &Rope) -> Result<Option<Self>, MixedIndentError> {
        let lines = rope.lines_raw(..);
        let mut tabs = false;
        let mut spaces: BTreeMap<usize, usize> = BTreeMap::new();

        for line in lines {
            match Indentation::parse_line(&line) {
                Ok(Some(Indentation::Spaces(size))) => {
                    let counter = spaces.entry(size).or_insert(0);
                    *counter += 1;
                }
                Ok(Some(Indentation::Tabs)) => tabs = true,
                Ok(None) => continue,
                Err(e) => return Err(e),
            }
        }

        match (tabs, !spaces.is_empty()) {
            (true, true) => Err(MixedIndentError),
            (true, false) => Ok(Some(Indentation::Tabs)),
            (false, true) => {
                let tab_size = extract_count(spaces);
                if tab_size > 0 {
                    Ok(Some(Indentation::Spaces(tab_size)))
                } else {
                    Ok(None)
                }
            },
            _ => Ok(None),
        }
    }

    /// Detects the indentation on a specific line.
    /// Parses whitespace until first occurrence of something else
    pub fn parse_line(line: &str) -> Result<Option<Self>, MixedIndentError> {
        let mut spaces = 0;

        for char in line.as_bytes() {
            match char {
                b' ' => spaces += 1,
                b'\t' if spaces > 0 => return Err(MixedIndentError),
                b'\t' => return Ok(Some(Indentation::Tabs)),
                _ => break,
            }
        }

        if spaces > 0 {
            Ok(Some(Indentation::Spaces(spaces)))
        } else {
            Ok(None)
        }
    }
}

/// Uses a heuristic to calculate the greatest common denominator of most used indentation depths.
///
/// As BTreeMaps are ordered by value, using take on the iterator ensures the indentation levels
/// most frequently used in the file are extracted.
fn extract_count(spaces: BTreeMap<usize, usize>) -> usize {
    let mut take_size = 4;

    if spaces.len() < take_size {
        take_size = spaces.len();
    }

    // Fold results using GCD, skipping numbers which result in gcd returning 1
    spaces.iter().take(take_size).fold(0, |a, (b, _)| {
        let d = gcd(a, *b);
        if d == 1 {
            a
        } else {
            d
        }
    })
}

/// Simple implementation to calculate greatest common divisor, based on Euclid's algorithm
fn gcd(a: usize, b: usize) -> usize {
    if a == 0 {
        b
    } else if b == 0 || a == b {
        a
    } else {
        let mut a = a;
        let mut b = b;

        while b > 0 {
            let r = a % b;
            a = b;
            b = r;
        }
        a
    }
}

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

    #[test]
    fn gcd_calculates_correctly() {
        assert_eq!(21, gcd(1071, 462));
        assert_eq!(6, gcd(270, 192));
    }

    #[test]
    fn line_gets_two_spaces() {
        let result = Indentation::parse_line("  ");
        let expected = Indentation::Spaces(2);

        assert_eq!(result.unwrap(), Some(expected));
    }

    #[test]
    fn line_gets_tabs() {
        let result = Indentation::parse_line("\t");
        let expected = Indentation::Tabs;

        assert_eq!(result.unwrap(), Some(expected));
    }

    #[test]
    fn line_errors_mixed_indent() {
        let result = Indentation::parse_line("  \t");
        assert!(result.is_err());
    }

    #[test]
    fn rope_gets_two_spaces() {
        let result = Indentation::parse(&Rope::from(
            r#"
        // This is a comment
          Testing
          Indented
            Even more indented
            # Comment
            # Comment
            # Comment
        "#,
        ));
        let expected = Indentation::Spaces(2);

        assert_eq!(result.unwrap(), Some(expected));
    }

    #[test]
    fn rope_gets_four_spaces() {
        let result = Indentation::parse(&Rope::from(
            r#"
        fn my_fun_func(&self,
                       another_arg: usize) -> Fun {
            /* Random comment describing program behavior */
            Fun::from(another_arg)
        }
        "#,
        ));
        let expected = Indentation::Spaces(4);

        assert_eq!(result.unwrap(), Some(expected));
    }
}
<|endoftext|>


<commit_before>/// Internal namespace.
pub( crate ) mod private
{
  use crate::prelude::*;

  macro_rules! NODE_ID
  {
    () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
  }

  macro_rules! EDGE_ID
  {
    () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphNodesNominalInterface
  {

    /// Handle of a node - entity representing a node or the node itself.
    /// It's not always possible to operate a node directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise NodeHandle could be &Node.
    type NodeHandle : NodeBasicInterface;

    /// Get node with id.
    fn node< Id >( &self, id : Id ) -> &Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    // /// Iterate over all nodes.
    // fn nodes< 'a, 'b >( &'a self )
    // ->
    // Box< dyn Iterator< Item = ( &NODE_ID!(), &Self::NodeHandle ) > + 'b >
    // where
    //   'a : 'b,
    // ;

    /// Iterate over neighbourhood of the node.
    fn out_nodes_ids< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = NODE_ID!() > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    ;

  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphEdgesNominalInterface
  where
    Self : GraphNodesNominalInterface,
  {

    /// Handle of an edge - entity representing an edge or the edge itself.
    /// It's not always possible to operate an edge directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise EdgeHandle could be &Node.
    type EdgeHandle : EdgeBasicInterface;

    /// Get edge with id.
    fn edge< Id >( &self, id : Id ) -> &Self::EdgeHandle
    where
      Id : Into< EDGE_ID!() >
    ;

    /// Iterate over output edges of the node.
    fn out_edges_ids< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = EDGE_ID!() > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    ;

    // /// Iterate over output edges of the node.
    // fn out_edges< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    // ->
    // Box< dyn Iterator< Item = ( &NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    // // Box< dyn Iterator< Item = EDGE_ID!() > + 'b >
    // where
    //   IntoId : Into< NODE_ID!() >,
    //   'a : 'b,
    // ;

  }

  ///
  /// Graph nodes of which is possible to enumerate.
  ///

  pub trait GraphNodesEnumerableInterface
  where
    Self : GraphNodesNominalInterface,
  {

    /// Iterate over all nodes.
    fn nodes< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( &NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of nodes. Order of the graph.
    fn nnodes( &self ) -> usize
    {
      self.nodes().count()
    }

  }

  ///
  /// Graph edges of which is possible to enumerate.
  ///

  pub trait GraphEdgesEnumerableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {

    /// Iterate over all edges.
    fn edges< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( &EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of edges. Size of the graph.
    fn nedges( &self ) -> usize
    {
      self.edges().count()
    }

  }

  ///
  /// Graph interface which allow to add more nodes. Know nothing about edges.
  ///

  pub trait GraphNodesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
    ,
  {

    /// Get node with id mutably.
    fn node_mut< Id >( &mut self, id : Id ) -> &mut Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    /// Add out nodes to the node.
    fn node_add_out_nodes< IntoId1, IntoId2, Iter >
    (
      &mut self,
      node_id : IntoId1,
      out_nodes_iter : Iter,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId2 : Into< NODE_ID!() >,
      Iter : IntoIterator< Item = IntoId2 >,
      Iter::IntoIter : Clone,
    ;

    /// Add out edges to the node.
    fn node_add_out_node< IntoId1, IntoId2 >
    (
      &mut self,
      node_id : IntoId1,
      out_node_id : IntoId2,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId1 : Clone,
      IntoId2 : Into< NODE_ID!() >,
      IntoId2 : Clone,
    {
      self.node_add_out_nodes( node_id, core::iter::once( out_node_id ) );
    }

    /// Either make new or get existing node.
    fn node_making< Id >( &mut self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    ;

    /// Make edges.
    fn make_with_edge_list< IntoIter, Id >( &mut self, into_iter : IntoIter )
    where
      Id : Into< NODE_ID!() >,
      IntoIter : IntoIterator< Item = Id >,
      IntoIter::IntoIter : core::iter::ExactSizeIterator< Item = Id >,
    {
      use wtools::iter::prelude::*;
      let iter = into_iter.into_iter();
      debug_assert_eq!( iter.len() % 2, 0 );
      for mut chunk in &iter.chunks( 2 )
      {
        let id1 = chunk.next().unwrap().into();
        let id2 = chunk.next().unwrap().into();
        self.node_making( id1 );
        self.node_making( id2 );
        self.node_add_out_node( id1, id2 );
      }

    }

  }

  ///
  /// Graph interface which allow to add more edges.
  ///

  pub trait GraphEdgesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
      GraphNodesExtendableInterface +
    ,
  {

    /// Either make new or get existing edge for specified nodes.
    fn _edge_id_generate( &mut self, node1 : NODE_ID!(), node2 : NODE_ID!() ) -> EDGE_ID!();

    /// Either make new or get existing edge for specified nodes.
    fn _edge_add( &mut self, edge_id : EDGE_ID!(), node1 : NODE_ID!(), node2 : NODE_ID!() );

    /// Either make new or get existing edge for specified nodes.
    fn _edge_make_for_nodes< IntoNodeId1, IntoNodeId2 >( &mut self, node1 : IntoNodeId1, node2 : IntoNodeId2 ) -> EDGE_ID!()
    where
      IntoNodeId1 : Into< NODE_ID!() >,
      IntoNodeId2 : Into< NODE_ID!() >,
    {
      let node1 = node1.into();
      let node2 = node2.into();
      let edge = self._edge_id_generate( node1, node2 );
      self._edge_add( edge, node1, node2 );
      edge
    }

  }

  ///
  /// Graph nodes of which has a kind.
  ///

  pub trait GraphKindGetterInterface
  where
    Self : GraphNodesNominalInterface,
  {
    /// Enumerate kinds of the node.
    type NodeKind : crate::NodeKindInterface;
    /// Get kind of the node.
    fn node_kind( &self, node_id : NODE_ID!() ) -> Self::NodeKind;
  }

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;
}

pub use protected::*;

/// Parented namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

pub use exposed::*;

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
  pub use super::private::
  {
    GraphNodesNominalInterface,
    GraphEdgesNominalInterface,
    GraphNodesEnumerableInterface,
    GraphEdgesEnumerableInterface,
    GraphNodesExtendableInterface,
    GraphEdgesExtendableInterface,
    GraphKindGetterInterface,
  };
}
<commit_msg>evolve graphs<commit_after>/// Internal namespace.
pub( crate ) mod private
{
  use crate::prelude::*;

  macro_rules! NODE_ID
  {
    () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
  }

  macro_rules! EDGE_ID
  {
    () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphNodesNominalInterface
  {

    /// Handle of a node - entity representing a node or the node itself.
    /// It's not always possible to operate a node directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise NodeHandle could be &Node.
    type NodeHandle : NodeBasicInterface;

    /// Get node with id.
    fn node< Id >( &self, id : Id ) -> &Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    /// Iterate over neighbourhood of the node. Callback gets ids of nodes in neighbourhood of a picked node.
    fn out_nodes_ids< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = NODE_ID!() > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    ;

    /// Iterate over neighbourhood of the node. Callback gets ids and reference on itself of nodes in neighbourhood of a picked node.
    fn out_nodes< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_nodes_ids( node_id ).map( | id |
      {
        ( id, self.node( id ) )
      }))
    }

  }

  ///
  /// Graph which know how to iterate neighbourhood of a node and capable to convert id of a node into a node.
  ///

  pub trait GraphEdgesNominalInterface
  where
    Self : GraphNodesNominalInterface,
  {

    /// Handle of an edge - entity representing an edge or the edge itself.
    /// It's not always possible to operate an edge directly, for example it it has to be wrapped by cell ref. For that use NodeHandle.
    /// Otherwise EdgeHandle could be &Node.
    type EdgeHandle : EdgeBasicInterface;

    /// Get edge with id.
    fn edge< Id >( &self, id : Id ) -> &Self::EdgeHandle
    where
      Id : Into< EDGE_ID!() >
    ;

    /// Iterate over output edges of the node. Callback gets ids of nodes in neighbourhood of a picked node.
    fn out_edges_ids< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = EDGE_ID!() > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    ;

    /// Iterate over output edges of the node. Callback gets ids and references of edges in neighbourhood of a picked node.
    fn out_edges< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_edges_ids( node_id ).map( | id |
      {
        ( id, self.edge( id ) )
      }))
    }

  }

  ///
  /// Graph nodes of which is possible to enumerate.
  ///

  pub trait GraphNodesEnumerableInterface
  where
    Self : GraphNodesNominalInterface,
  {

    /// Iterate over all nodes.
    fn nodes< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( &NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of nodes. Order of the graph.
    fn nnodes( &self ) -> usize
    {
      self.nodes().count()
    }

  }

  ///
  /// Graph edges of which is possible to enumerate.
  ///

  pub trait GraphEdgesEnumerableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {

    /// Iterate over all edges.
    fn edges< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( &EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      'a : 'b,
    ;

    /// Number of edges. Size of the graph.
    fn nedges( &self ) -> usize
    {
      self.edges().count()
    }

  }

  ///
  /// Graph interface which allow to add more nodes. Know nothing about edges.
  ///

  pub trait GraphNodesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
    ,
  {

    /// Get node with id mutably.
    fn node_mut< Id >( &mut self, id : Id ) -> &mut Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;

    /// Add out nodes to the node.
    fn node_add_out_nodes< IntoId1, IntoId2, Iter >
    (
      &mut self,
      node_id : IntoId1,
      out_nodes_iter : Iter,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId2 : Into< NODE_ID!() >,
      Iter : IntoIterator< Item = IntoId2 >,
      Iter::IntoIter : Clone,
    ;

    /// Add out edges to the node.
    fn node_add_out_node< IntoId1, IntoId2 >
    (
      &mut self,
      node_id : IntoId1,
      out_node_id : IntoId2,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId1 : Clone,
      IntoId2 : Into< NODE_ID!() >,
      IntoId2 : Clone,
    {
      self.node_add_out_nodes( node_id, core::iter::once( out_node_id ) );
    }

    /// Either make new or get existing node.
    fn node_making< Id >( &mut self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    ;

    /// Make edges.
    fn make_with_edge_list< IntoIter, Id >( &mut self, into_iter : IntoIter )
    where
      Id : Into< NODE_ID!() >,
      IntoIter : IntoIterator< Item = Id >,
      IntoIter::IntoIter : core::iter::ExactSizeIterator< Item = Id >,
    {
      use wtools::iter::prelude::*;
      let iter = into_iter.into_iter();
      debug_assert_eq!( iter.len() % 2, 0 );
      for mut chunk in &iter.chunks( 2 )
      {
        let id1 = chunk.next().unwrap().into();
        let id2 = chunk.next().unwrap().into();
        self.node_making( id1 );
        self.node_making( id2 );
        self.node_add_out_node( id1, id2 );
      }

    }

  }

  ///
  /// Graph interface which allow to add more edges.
  ///

  pub trait GraphEdgesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
      GraphNodesExtendableInterface +
    ,
  {

    /// Either make new or get existing edge for specified nodes.
    fn _edge_id_generate( &mut self, node1 : NODE_ID!(), node2 : NODE_ID!() ) -> EDGE_ID!();

    /// Either make new or get existing edge for specified nodes.
    fn _edge_add( &mut self, edge_id : EDGE_ID!(), node1 : NODE_ID!(), node2 : NODE_ID!() );

    /// Either make new or get existing edge for specified nodes.
    fn _edge_make_for_nodes< IntoNodeId1, IntoNodeId2 >( &mut self, node1 : IntoNodeId1, node2 : IntoNodeId2 ) -> EDGE_ID!()
    where
      IntoNodeId1 : Into< NODE_ID!() >,
      IntoNodeId2 : Into< NODE_ID!() >,
    {
      let node1 = node1.into();
      let node2 = node2.into();
      let edge = self._edge_id_generate( node1, node2 );
      self._edge_add( edge, node1, node2 );
      edge
    }

  }

  ///
  /// Graph nodes of which has a kind.
  ///

  pub trait GraphKindGetterInterface
  where
    Self : GraphNodesNominalInterface,
  {
    /// Enumerate kinds of the node.
    type NodeKind : crate::NodeKindInterface;
    /// Get kind of the node.
    fn node_kind( &self, node_id : NODE_ID!() ) -> Self::NodeKind;
  }

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;
}

pub use protected::*;

/// Parented namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
}

pub use exposed::*;

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
  pub use super::private::
  {
    GraphNodesNominalInterface,
    GraphEdgesNominalInterface,
    GraphNodesEnumerableInterface,
    GraphEdgesEnumerableInterface,
    GraphNodesExtendableInterface,
    GraphEdgesExtendableInterface,
    GraphKindGetterInterface,
  };
}
<|endoftext|>


<commit_before>#![feature(slicing_syntax)]

extern crate test;
extern crate time;

use std::io::stdio;
use std::os;

fn solution() -> u32 {
    use std::iter::AdditiveIterator;

    range(0u32, 1_000).filter(|x| x % 3 == 0 || x % 5 == 0).sum()
}

// XXX "Imperative" style, roughly the same speed
//fn solution() -> u32 {
    //let mut sum = 0;

    //for x in range(0, 1_000) {
        //if x % 3 == 0 || x % 5 == 0 {
            //sum += x;
        //}
    //}

    //sum
//}

fn main() {
    match os::args()[] {
        [_, ref flag] if flag[] == "-a" => return println!("{}", solution()),
        _ => {},
    }

    for line in stdio::stdin().lines() {
        let iters: u64 = from_str(line.unwrap()[].trim()).unwrap();

        let start = time::precise_time_ns();
        for _ in range(0, iters) {
            test::black_box(solution());
        }
        let end = time::precise_time_ns();

        println!("{}", end - start);
    }
}
<commit_msg>fix(001.rs): fix fallout of recent changes in operator dispatch<commit_after>#![feature(slicing_syntax)]

extern crate test;
extern crate time;

use std::io::stdio;
use std::os;

fn solution() -> u32 {
    use std::iter::AdditiveIterator;

    range(0u32, 1_000).filter(|&x| x % 3 == 0 || x % 5 == 0).sum()
}

// XXX "Imperative" style, roughly the same speed
//fn solution() -> u32 {
    //let mut sum = 0;

    //for x in range(0, 1_000) {
        //if x % 3 == 0 || x % 5 == 0 {
            //sum += x;
        //}
    //}

    //sum
//}

fn main() {
    match os::args()[] {
        [_, ref flag] if flag[] == "-a" => return println!("{}", solution()),
        _ => {},
    }

    for line in stdio::stdin().lines() {
        let iters: u64 = from_str(line.unwrap()[].trim()).unwrap();

        let start = time::precise_time_ns();
        for _ in range(0, iters) {
            test::black_box(solution());
        }
        let end = time::precise_time_ns();

        println!("{}", end - start);
    }
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

//TODO: if bigint feature, use i64 displacement args instead of i32

use crate::register::{register_to_iced, Register};
use wasm_bindgen::prelude::*;

/// Memory operand passed to one of [`Instruction`]'s `create*()` constructor methods
///
/// [`Instruction`]: struct.Instruction.html
#[wasm_bindgen]
pub struct MemoryOperand(pub(crate) iced_x86_rust::MemoryOperand);

#[wasm_bindgen]
impl MemoryOperand {
	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(constructor)]
	pub fn new(
		base: Register, index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32,
		#[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::new(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "new64")]
	pub fn new64(
		base: Register, index: Register, scale: u32, displacement: u64, #[allow(non_snake_case)] displSize: u32,
		#[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::new(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement as i64,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleBcstSeg")]
	pub fn with_base_index_scale_bcst_seg(
		base: Register, index: Register, scale: u32, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_bcst_seg(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSizeBcstSeg")]
	pub fn with_base_displ_size_bcst_seg(
		base: Register, displacement: i64, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size_bcst_seg(
			register_to_iced(base),
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSizeBcstSeg")]
	pub fn with_index_scale_displ_size_bcst_seg(
		index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size_bcst_seg(
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplBcstSeg")]
	pub fn with_base_displ_bcst_seg(
		base: Register, displacement: i64, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_bcst_seg(
			register_to_iced(base),
			displacement,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleDisplSize")]
	pub fn with_base_index_scale_displ_size(
		base: Register, index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_displ_size(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScale")]
	pub fn with_base_index_scale(base: Register, index: Register, scale: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale(register_to_iced(base), register_to_iced(index), scale))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndex")]
	pub fn with_base_index(base: Register, index: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index(register_to_iced(base), register_to_iced(index)))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSize")]
	pub fn with_base_displ_size(base: Register, displacement: i64, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size(register_to_iced(base), displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSize")]
	pub fn with_index_scale_displ_size(index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size(register_to_iced(index), scale, displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDispl")]
	pub fn with_base_displ(base: Register, displacement: i64) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ(register_to_iced(base), displacement))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBase")]
	pub fn with_base(base: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base(register_to_iced(base)))
	}
}
<commit_msg>Remove fixed todo<commit_after>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::register::{register_to_iced, Register};
use wasm_bindgen::prelude::*;

/// Memory operand passed to one of [`Instruction`]'s `create*()` constructor methods
///
/// [`Instruction`]: struct.Instruction.html
#[wasm_bindgen]
pub struct MemoryOperand(pub(crate) iced_x86_rust::MemoryOperand);

#[wasm_bindgen]
impl MemoryOperand {
	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(constructor)]
	pub fn new(
		base: Register, index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32,
		#[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::new(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "new64")]
	pub fn new64(
		base: Register, index: Register, scale: u32, displacement: u64, #[allow(non_snake_case)] displSize: u32,
		#[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::new(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement as i64,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleBcstSeg")]
	pub fn with_base_index_scale_bcst_seg(
		base: Register, index: Register, scale: u32, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_bcst_seg(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSizeBcstSeg")]
	pub fn with_base_displ_size_bcst_seg(
		base: Register, displacement: i64, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size_bcst_seg(
			register_to_iced(base),
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSizeBcstSeg")]
	pub fn with_index_scale_displ_size_bcst_seg(
		index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size_bcst_seg(
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `isBroadcast`: `true` if it's broadcast memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplBcstSeg")]
	pub fn with_base_displ_bcst_seg(
		base: Register, displacement: i64, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_bcst_seg(
			register_to_iced(base),
			displacement,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleDisplSize")]
	pub fn with_base_index_scale_displ_size(
		base: Register, index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_displ_size(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScale")]
	pub fn with_base_index_scale(base: Register, index: Register, scale: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale(register_to_iced(base), register_to_iced(index), scale))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndex")]
	pub fn with_base_index(base: Register, index: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index(register_to_iced(base), register_to_iced(index)))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSize")]
	pub fn with_base_displ_size(base: Register, displacement: i64, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size(register_to_iced(base), displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSize")]
	pub fn with_index_scale_displ_size(index: Register, scale: u32, displacement: i64, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size(register_to_iced(index), scale, displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDispl")]
	pub fn with_base_displ(base: Register, displacement: i64) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ(register_to_iced(base), displacement))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBase")]
	pub fn with_base(base: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base(register_to_iced(base)))
	}
}
<|endoftext|>