<commit_before>use if_chain::if_chain;
use rustc::hir::{Expr, ExprKind};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};

use crate::consts::{constant, Constant};
use crate::syntax::ast::LitKind;
use crate::utils::{in_macro, is_direct_expn_of, span_help_and_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls.
    ///
    /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a
    /// panic!() or unreachable!()
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// assert!(false)
    /// // or
    /// assert!(true)
    /// // or
    /// const B: bool = false;
    /// assert!(B)
    /// ```
    pub ASSERTIONS_ON_CONSTANTS,
    style,
    "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
}

declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        let mut is_debug_assert = false;
        if_chain! {
            if let Some(assert_span) = is_direct_expn_of(e.span, "assert");
            if !in_macro(assert_span)
                || is_direct_expn_of(assert_span, "debug_assert").map_or(false, |span| {
                    is_debug_assert = true;
                    // Check that `debug_assert!` itself is not inside a macro
                    !in_macro(span)
                });
            if let ExprKind::Unary(_, ref lit) = e.node;
            then {
                if let ExprKind::Lit(ref inner) = lit.node {
                    match inner.node {
                        LitKind::Bool(true) => {
                            span_help_and_lint(cx, ASSERTIONS_ON_CONSTANTS, e.span,
                                "assert!(true) will be optimized out by the compiler",
                                "remove it");
                        },
                        LitKind::Bool(false) if !is_debug_assert => {
                            span_help_and_lint(
                                cx, ASSERTIONS_ON_CONSTANTS, e.span,
                                "assert!(false) should probably be replaced",
                                "use panic!() or unreachable!()");
                        },
                        _ => (),
                    }
                } else if let Some(bool_const) = constant(cx, cx.tables, lit) {
                    match bool_const.0 {
                        Constant::Bool(true) => {
                            span_help_and_lint(cx, ASSERTIONS_ON_CONSTANTS, e.span,
                                "assert!(const: true) will be optimized out by the compiler",
                                "remove it");
                        },
                        Constant::Bool(false) if !is_debug_assert => {
                            span_help_and_lint(cx, ASSERTIONS_ON_CONSTANTS, e.span,
                                "assert!(const: false) should probably be replaced",
                                "use panic!() or unreachable!()");
                        },
                        _ => (),
                    }
                }
            }
        }
    }
}
<commit_msg>Format code<commit_after>use if_chain::if_chain;
use rustc::hir::{Expr, ExprKind};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};

use crate::consts::{constant, Constant};
use crate::syntax::ast::LitKind;
use crate::utils::{in_macro, is_direct_expn_of, span_help_and_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls.
    ///
    /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a
    /// panic!() or unreachable!()
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// assert!(false)
    /// // or
    /// assert!(true)
    /// // or
    /// const B: bool = false;
    /// assert!(B)
    /// ```
    pub ASSERTIONS_ON_CONSTANTS,
    style,
    "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
}

declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        let mut is_debug_assert = false;
        if_chain! {
            if let Some(assert_span) = is_direct_expn_of(e.span, "assert");
            if !in_macro(assert_span)
                || is_direct_expn_of(assert_span, "debug_assert").map_or(false, |span| {
                    is_debug_assert = true;
                    // Check that `debug_assert!` itself is not inside a macro
                    !in_macro(span)
                });
            if let ExprKind::Unary(_, ref lit) = e.node;
            then {
                if let ExprKind::Lit(ref inner) = lit.node {
                    match inner.node {
                        LitKind::Bool(true) => {
                            span_help_and_lint(
                                cx,
                                ASSERTIONS_ON_CONSTANTS,
                                e.span,
                                "`assert!(true)` will be optimized out by the compiler",
                                "remove it"
                            );
                        },
                        LitKind::Bool(false) if !is_debug_assert => {
                            span_help_and_lint(
                                cx,
                                ASSERTIONS_ON_CONSTANTS,
                                e.span,
                                "`assert!(false)` should probably be replaced",
                                "use `panic!()` or `unreachable!()`"
                            );
                        },
                        _ => (),
                    }
                } else if let Some(bool_const) = constant(cx, cx.tables, lit) {
                    match bool_const.0 {
                        Constant::Bool(true) => {
                            span_help_and_lint(
                                cx,
                                ASSERTIONS_ON_CONSTANTS,
                                e.span,
                                "`assert!(const: true)` will be optimized out by the compiler",
                                "remove it"
                            );
                        },
                        Constant::Bool(false) if !is_debug_assert => {
                            span_help_and_lint(
                                cx,
                                ASSERTIONS_ON_CONSTANTS,
                                e.span,
                                "`assert!(const: false)` should probably be replaced",
                                "use `panic!()` or `unreachable!()`"
                            );
                        },
                        _ => (),
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{is_direct_expn_of, span_lint};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::map::Map;
use rustc::ty;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for function/method calls with a mutable
    /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
    ///
    /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the
    /// compiler.
    /// Therefore mutating something in a `debug_assert!` macro results in different behaviour
    /// between a release and debug build.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// debug_assert_eq!(vec![3].pop(), Some(3));
    /// // or
    /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
    /// debug_assert!(take_a_mut_parameter(&mut 5));
    /// ```
    pub DEBUG_ASSERT_WITH_MUT_CALL,
    correctness,
    "mutable arguments in `debug_assert{,_ne,_eq}!`"
}

declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);

const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        for dmn in &DEBUG_MACRO_NAMES {
            if is_direct_expn_of(e.span, dmn).is_some() {
                if let Some(span) = extract_call(cx, e) {
                    span_lint(
                        cx,
                        DEBUG_ASSERT_WITH_MUT_CALL,
                        span,
                        &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
                    );
                }
            }
        }
    }
}

//HACK(hellow554): remove this when #4694 is implemented
#[allow(clippy::cognitive_complexity)]
fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<Span> {
    if_chain! {
        if let ExprKind::Block(ref block, _) = e.kind;
        if block.stmts.len() == 1;
        if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind;
        then {
            if_chain! {
                if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
                if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
                if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
                then {
                    // debug_assert
                    let mut visitor = MutArgVisitor::new(cx);
                    visitor.visit_expr(condition);
                    return visitor.expr_span();
                } else {
                    // debug_assert_{eq,ne}
                    if_chain! {
                        if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
                        if let Some(ref matchheader) = matchblock.expr;
                        if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
                        if let ExprKind::Tup(ref conditions) = headerexpr.kind;
                        if conditions.len() == 2;
                        then {
                            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind {
                                let mut visitor = MutArgVisitor::new(cx);
                                visitor.visit_expr(lhs);
                                if let Some(span) = visitor.expr_span() {
                                    return Some(span);
                                }
                            }
                            if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind {
                                let mut visitor = MutArgVisitor::new(cx);
                                visitor.visit_expr(rhs);
                                if let Some(span) = visitor.expr_span() {
                                    return Some(span);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    None
}

struct MutArgVisitor<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    expr_span: Option<Span>,
    found: bool,
}

impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx,
            expr_span: None,
            found: false,
        }
    }

    fn expr_span(&self) -> Option<Span> {
        if self.found {
            self.expr_span
        } else {
            None
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        match expr.kind {
            ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                self.found = true;
                return;
            },
            ExprKind::Path(_) => {
                if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
                    if adj
                        .iter()
                        .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
                    {
                        self.found = true;
                        return;
                    }
                }
            },
            _ if !self.found => self.expr_span = Some(expr.span),
            _ => return,
        }
        walk_expr(self, expr)
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}
<commit_msg>Small refactor of mutable_debug_assertions<commit_after>use crate::utils::{is_direct_expn_of, span_lint};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::map::Map;
use rustc::ty;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for function/method calls with a mutable
    /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
    ///
    /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the
    /// compiler.
    /// Therefore mutating something in a `debug_assert!` macro results in different behaviour
    /// between a release and debug build.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust,ignore
    /// debug_assert_eq!(vec![3].pop(), Some(3));
    /// // or
    /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
    /// debug_assert!(take_a_mut_parameter(&mut 5));
    /// ```
    pub DEBUG_ASSERT_WITH_MUT_CALL,
    correctness,
    "mutable arguments in `debug_assert{,_ne,_eq}!`"
}

declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);

const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        for dmn in &DEBUG_MACRO_NAMES {
            if is_direct_expn_of(e.span, dmn).is_some() {
                if let Some(span) = extract_call(cx, e) {
                    span_lint(
                        cx,
                        DEBUG_ASSERT_WITH_MUT_CALL,
                        span,
                        &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
                    );
                }
            }
        }
    }
}

//HACK(hellow554): remove this when #4694 is implemented
#[allow(clippy::cognitive_complexity)]
fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<Span> {
    if_chain! {
        if let ExprKind::Block(ref block, _) = e.kind;
        if block.stmts.len() == 1;
        if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind;
        then {
            // debug_assert
            if_chain! {
                if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
                if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
                if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
                then {
                    let mut visitor = MutArgVisitor::new(cx);
                    visitor.visit_expr(condition);
                    return visitor.expr_span();
                }
            }

            // debug_assert_{eq,ne}
            if_chain! {
                if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
                if let Some(ref matchheader) = matchblock.expr;
                if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
                if let ExprKind::Tup(ref conditions) = headerexpr.kind;
                if conditions.len() == 2;
                then {
                    if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind {
                        let mut visitor = MutArgVisitor::new(cx);
                        visitor.visit_expr(lhs);
                        if let Some(span) = visitor.expr_span() {
                            return Some(span);
                        }
                    }
                    if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind {
                        let mut visitor = MutArgVisitor::new(cx);
                        visitor.visit_expr(rhs);
                        if let Some(span) = visitor.expr_span() {
                            return Some(span);
                        }
                    }
                }
            }
        }
    }

    None
}

struct MutArgVisitor<'a, 'tcx> {
    cx: &'a LateContext<'a, 'tcx>,
    expr_span: Option<Span>,
    found: bool,
}

impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx,
            expr_span: None,
            found: false,
        }
    }

    fn expr_span(&self) -> Option<Span> {
        if self.found {
            self.expr_span
        } else {
            None
        }
    }
}

impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        match expr.kind {
            ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                self.found = true;
                return;
            },
            ExprKind::Path(_) => {
                if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
                    if adj
                        .iter()
                        .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
                    {
                        self.found = true;
                        return;
                    }
                }
            },
            _ if !self.found => self.expr_span = Some(expr.span),
            _ => return,
        }
        walk_expr(self, expr)
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}
<|endoftext|>


<commit_before>use super::namepart::{Category, NamePart};
use phf::phf_set;

static VOWELLESS_SURNAMES: [&str; 4] = ["Ng", "Lv", "Mtz", "Hdz"];

static SINGLE_LETTER_CONJUNCTIONS: [&str; 4] = ["e", "y", "E", "Y"];

// Uncapitalized list should match UNCAPITALIZED_PARTICLES in `namecase.rs`
//
// Unfortunately, the duplication between the lists is necessary because of the
// way `phf_set!` works, and the duplication within this list is necessary
// because we may or may not lowercase the particle as part of first-pass
// namecasing, depending on whether the input is given with mixed case.
static SURNAME_PREFIXES: phf::Set<&'static str> = phf_set! {
    "af",
    "av",
    "da",
    "das",
    "dal",
    "de",
    "del",
    "dela",
    "dei",
    "der",
    "di",
    "dí",
    "do",
    "dos",
    "du",
    "la",
    "le",
    "na",
    "ter",
    "van",
    "vel",
    "von",
    "zu",
    "zum",
    "Abu",
    "Abd",
    "Af",
    "Al",
    "Ap",
    "Av",
    "Aw",
    "Bar",
    "Ben",
    "Bon",
    "Bin",
    "Da",
    "Das",
    "Dal",
    "De",
    "Dei",
    "Del",
    "Dela",
    "Den",
    "Der",
    "Di",
    "Dí",
    "Do",
    "Dos",
    "Du",
    "El",
    "Ibn",
    "La",
    "Le",
    "Lo",
    "Na",
    "Nic",
    "San",
    "Santa",
    "St",
    "Ste",
    "Ter",
    "Van",
    "Vel",
    "Von",
    "Zu",
    "Zum",
};

pub fn is_vowelless_surname(word: &str, use_capitalization: bool) -> bool {
    if use_capitalization {
        VOWELLESS_SURNAMES.contains(&word)
    } else {
        VOWELLESS_SURNAMES
            .iter()
            .any(|surname| surname.eq_ignore_ascii_case(word))
    }
}

pub fn find_surname_index(words: &[NamePart]) -> usize {
    if words.len() < 2 {
        return 0;
    }

    for (i, word) in words[0..words.len() - 1].iter().enumerate() {
        let key: &str = match word.category {
            Category::Name(ref namecased) => namecased,
            _ => word.word,
        };
        if SURNAME_PREFIXES.contains(key) {
            return i;
        }

        if i > 0 && SINGLE_LETTER_CONJUNCTIONS.contains(&word.word) {
            // We found what looks like a conjunction in a Spanish or Portuguese
            // style surname (e.g. "Romero y Galdámez" or "Dato e Iradier"), so
            // the previous word was the start of the surname
            if !words[i - 1].is_initials() && !words[i + 1].is_initials() {
                return i - 1;
            }
        }
    }

    // Default case: just assume the last word is the surname
    words.len() - 1
}

#[cfg(test)]
mod tests {
    use super::super::namepart::{Location, NamePart};
    use super::*;

    #[test]
    fn one_word() {
        let parts: Vec<_> = NamePart::all_from_text("Doe", true, Location::Start).collect();
        assert_eq!(0, find_surname_index(&*parts));
    }

    #[test]
    fn two_words() {
        let parts: Vec<_> = NamePart::all_from_text("Jane Doe", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn three_words() {
        let parts: Vec<_> =
            NamePart::all_from_text("Jane Emily Doe", true, Location::Start).collect();
        assert_eq!(2, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_after_nothing() {
        let parts: Vec<_> = NamePart::all_from_text("y Velazquez", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_after_one() {
        let parts: Vec<_> =
            NamePart::all_from_text("Rodrigo y Velazquez", true, Location::Start).collect();
        assert_eq!(0, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_after_two() {
        let parts: Vec<_> =
            NamePart::all_from_text("Jane Rodrigo y Velazquez", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn particle_after_nothing() {
        let parts: Vec<_> =
            NamePart::all_from_text("Abd al-Qader", true, Location::Start).collect();
        assert_eq!(0, find_surname_index(&*parts));
    }

    #[test]
    fn particle_after_one() {
        let parts: Vec<_> =
            NamePart::all_from_text("Jane Abd al-Qader", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn particle_and_conjunction() {
        let parts: Vec<_> =
            NamePart::all_from_text("Alejandro de Aza y Cabra", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_and_particle() {
        let parts: Vec<_> =
            NamePart::all_from_text("Alejandro Cabra y de Aza", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }
}
<commit_msg>Minor extra surname cases<commit_after>use super::namepart::{Category, NamePart};
use phf::phf_set;

static VOWELLESS_SURNAMES: [&str; 4] = ["Ng", "Lv", "Mtz", "Hdz"];

static SINGLE_LETTER_CONJUNCTIONS: [&str; 4] = ["e", "y", "E", "Y"];

// Uncapitalized list should match UNCAPITALIZED_PARTICLES in `namecase.rs`
//
// Unfortunately, the duplication between the lists is necessary because of the
// way `phf_set!` works, and the duplication within this list is necessary
// because we may or may not lowercase the particle as part of first-pass
// namecasing, depending on whether the input is given with mixed case.
static SURNAME_PREFIXES: phf::Set<&'static str> = phf_set! {
    "af",
    "av",
    "da",
    "das",
    "dal",
    "de",
    "del",
    "dela",
    "dei",
    "der",
    "di",
    "dí",
    "do",
    "dos",
    "du",
    "la",
    "le",
    "na",
    "ter",
    "van",
    "vel",
    "von",
    "zu",
    "zum",
    "Abu",
    "Abd",
    "Af",
    "Al",
    "Ap",
    "Av",
    "Aw",
    "Bar",
    "Ben",
    "Bon",
    "Bin",
    "Da",
    "Das",
    "Dal",
    "De",
    "Dei",
    "Del",
    "Dela",
    "Della",
    "Den",
    "Der",
    "Di",
    "Dí",
    "Do",
    "Dos",
    "Du",
    "El",
    "Ibn",
    "La",
    "Le",
    "Lo",
    "Na",
    "Nic",
    "San",
    "Santa",
    "St",
    "Ste",
    "Ter",
    "Van",
    "Vanden",
    "Vel",
    "Von",
    "Zu",
    "Zum",
};

pub fn is_vowelless_surname(word: &str, use_capitalization: bool) -> bool {
    if use_capitalization {
        VOWELLESS_SURNAMES.contains(&word)
    } else {
        VOWELLESS_SURNAMES
            .iter()
            .any(|surname| surname.eq_ignore_ascii_case(word))
    }
}

pub fn find_surname_index(words: &[NamePart]) -> usize {
    if words.len() < 2 {
        return 0;
    }

    for (i, word) in words[0..words.len() - 1].iter().enumerate() {
        let key: &str = match word.category {
            Category::Name(ref namecased) => namecased,
            _ => word.word,
        };
        if SURNAME_PREFIXES.contains(key) {
            return i;
        }

        if i > 0 && SINGLE_LETTER_CONJUNCTIONS.contains(&word.word) {
            // We found what looks like a conjunction in a Spanish or Portuguese
            // style surname (e.g. "Romero y Galdámez" or "Dato e Iradier"), so
            // the previous word was the start of the surname
            if !words[i - 1].is_initials() && !words[i + 1].is_initials() {
                return i - 1;
            }
        }
    }

    // Default case: just assume the last word is the surname
    words.len() - 1
}

#[cfg(test)]
mod tests {
    use super::super::namepart::{Location, NamePart};
    use super::*;

    #[test]
    fn one_word() {
        let parts: Vec<_> = NamePart::all_from_text("Doe", true, Location::Start).collect();
        assert_eq!(0, find_surname_index(&*parts));
    }

    #[test]
    fn two_words() {
        let parts: Vec<_> = NamePart::all_from_text("Jane Doe", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn three_words() {
        let parts: Vec<_> =
            NamePart::all_from_text("Jane Emily Doe", true, Location::Start).collect();
        assert_eq!(2, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_after_nothing() {
        let parts: Vec<_> = NamePart::all_from_text("y Velazquez", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_after_one() {
        let parts: Vec<_> =
            NamePart::all_from_text("Rodrigo y Velazquez", true, Location::Start).collect();
        assert_eq!(0, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_after_two() {
        let parts: Vec<_> =
            NamePart::all_from_text("Jane Rodrigo y Velazquez", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn particle_after_nothing() {
        let parts: Vec<_> =
            NamePart::all_from_text("Abd al-Qader", true, Location::Start).collect();
        assert_eq!(0, find_surname_index(&*parts));
    }

    #[test]
    fn particle_after_one() {
        let parts: Vec<_> =
            NamePart::all_from_text("Jane Abd al-Qader", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn particle_and_conjunction() {
        let parts: Vec<_> =
            NamePart::all_from_text("Alejandro de Aza y Cabra", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }

    #[test]
    fn conjunction_and_particle() {
        let parts: Vec<_> =
            NamePart::all_from_text("Alejandro Cabra y de Aza", true, Location::Start).collect();
        assert_eq!(1, find_surname_index(&*parts));
    }
}
<|endoftext|>


<commit_before>#[cfg(unix)]
use std::path::PathBuf;
use std::{
    fmt::{self, Debug, Display},
    io,
    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
    time::Duration,
};

use async_trait::async_trait;
use byteorder::{BigEndian, ByteOrder};
use bytes::{BufMut, BytesMut};
use log::trace;
use rand::Rng;
#[cfg(unix)]
use tokio::net::UnixStream;
use tokio::{
    io::{AsyncReadExt, AsyncWriteExt},
    time,
};
use trust_dns_proto::{
    op::{Message, Query},
    rr::{DNSClass, Name, RData, RecordType},
};

use crate::{
    config::{Config, LocalDnsAddr, Mode, ServerConfig},
    context::{Context, SharedContext},
    relay::{
        loadbalancing::server::{PlainPingBalancer, ServerType},
        socks5::Address,
        sys::{create_outbound_udp_socket, tcp_stream_connect},
        tcprelay::ProxyStream,
        udprelay::client::ServerClient as UdpServerClient,
    },
};

#[derive(Debug)]
pub enum LocalUpstream {
    TcpAndUdp(TcpUpstream, UdpUpstream),
    #[cfg(unix)]
    UnixSocket(UnixSocketUpstream),
}

impl Display for LocalUpstream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            LocalUpstream::TcpAndUdp(ref t, ..) => write!(f, "tcp+udp://{}", t.server),
            #[cfg(unix)]
            LocalUpstream::UnixSocket(ref u) => write!(f, "unix://{}", u.path.display()),
        }
    }
}

impl LocalUpstream {
    pub fn new(config: &Config) -> LocalUpstream {
        match config.local_dns_addr {
            Some(LocalDnsAddr::SocketAddr(ns)) => {
                LocalUpstream::TcpAndUdp(TcpUpstream { server: ns }, UdpUpstream { server: ns })
            }
            #[cfg(unix)]
            Some(LocalDnsAddr::UnixSocketAddr(ref p)) => {
                LocalUpstream::UnixSocket(UnixSocketUpstream { path: p.clone() })
            }
            None => panic!("LocalUpstream requires config.local_dns_addr"),
        }
    }

    pub async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message> {
        match self {
            LocalUpstream::TcpAndUdp(tcp, udp) => {
                // UDP than TCP.
                // Because UDP should always be faster than TCP.

                match time::timeout(Duration::from_secs(2), udp.lookup(context, query)).await {
                    Ok(Ok(message)) => Ok(message),
                    Ok(Err(..)) | Err(..) => {
                        trace!(
                            "LocalUpstream {} UDP query failed, continue with TCP query, {:?}",
                            udp.server,
                            query
                        );

                        tcp.lookup(context, query).await
                    }
                }
            }
            #[cfg(unix)]
            LocalUpstream::UnixSocket(upstream) => upstream.lookup(context, query).await,
        }
    }

    pub async fn lookup_ip(&self, context: &Context, host: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
        let mut name = Name::from_utf8(host)?;
        name.set_fqdn(true);

        let mut queryv4 = Query::new();
        queryv4.set_query_class(DNSClass::IN);
        queryv4.set_name(name);

        let mut queryv6 = queryv4.clone();
        queryv4.set_query_type(RecordType::A);
        queryv6.set_query_type(RecordType::AAAA);

        let (responsev4, responsev6) =
            tokio::try_join!(self.lookup(context, &queryv4), self.lookup(context, &queryv6))?;

        macro_rules! parse {
            ($response:expr) => {
                $response.answers().iter().filter_map(|rec| match rec.rdata() {
                    RData::A(ref ip) => Some(SocketAddr::new(IpAddr::V4(ip.clone()), port)),
                    RData::AAAA(ref ip) => Some(SocketAddr::new(IpAddr::V6(ip.clone()), port)),
                    _ => None,
                })
            };
        }
        Ok(parse!(responsev4).chain(parse!(responsev6)).collect())
    }
}

#[async_trait]
pub trait Upstream {
    async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message>;
}

fn generate_query_message(query: &Query) -> Message {
    let mut message = Message::new();
    message.set_id(rand::thread_rng().gen());
    message.set_recursion_desired(true);
    message.add_query(query.clone());
    message
}

pub async fn read_message<T: AsyncReadExt + Unpin>(stream: &mut T) -> io::Result<Message> {
    let mut res_buffer = [0; 2];
    stream.read_exact(&mut res_buffer).await?;

    let size = BigEndian::read_u16(&res_buffer) as usize;
    let mut res_buffer = vec![0; size];
    stream.read_exact(&mut res_buffer).await?;

    Ok(Message::from_vec(&res_buffer)?)
}

pub async fn write_message<T: AsyncWriteExt + Unpin>(stream: &mut T, message: &Message) -> io::Result<()> {
    let req_buffer = message.to_vec()?;
    let size = req_buffer.len();

    let mut send_buffer = BytesMut::with_capacity(2 + size);
    send_buffer.put_u16(size as u16);
    send_buffer.put_slice(&req_buffer);

    stream.write_all(&send_buffer).await
}

async fn stream_lookup<T>(query: &Query, stream: &mut T) -> io::Result<Message>
where
    T: AsyncReadExt + AsyncWriteExt + Unpin,
{
    write_message(stream, &generate_query_message(query)).await?;
    read_message(stream).await
}

pub struct UdpUpstream {
    pub server: SocketAddr,
}

impl Debug for UdpUpstream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("UdpUpstream").field("ns", &self.server).finish()
    }
}

#[async_trait]
impl Upstream for UdpUpstream {
    async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message> {
        // TODO: Reuse UdpSocket for sending queries

        trace!("DNS local UDP query {:?} to {}", query, self.server);

        let local_addr = SocketAddr::new(
            match self.server {
                SocketAddr::V4(..) => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
                SocketAddr::V6(..) => IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
            },
            0,
        );
        let socket = create_outbound_udp_socket(&local_addr, context.config()).await?;

        socket.connect(self.server).await?;
        socket.send(&generate_query_message(query).to_vec()?).await?;
        let mut response = vec![0; 512];
        let len = socket.recv(&mut response).await?;
        Ok(Message::from_vec(&response[..len])?)
    }
}

#[derive(Debug)]
pub struct TcpUpstream {
    pub server: SocketAddr,
}

#[async_trait]
impl Upstream for TcpUpstream {
    async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message> {
        // TODO: Reuse UdpSocket for sending queries

        trace!("DNS local TCP query {:?} to {}", query, self.server);

        let mut stream = tcp_stream_connect(&self.server, context.config()).await?;
        stream_lookup(query, &mut stream).await
    }
}

enum ProxyUpstreamMode {
    TcpOnly {
        balancer: PlainPingBalancer,
    },
    UdpOnly {
        balancer: PlainPingBalancer,
    },
    TcpAndUdp {
        tcp_balancer: PlainPingBalancer,
        udp_balancer: PlainPingBalancer,
    },
}

impl Debug for ProxyUpstreamMode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ProxyUpstreamMode::TcpOnly { .. } => f.write_str("TcpOnly"),
            ProxyUpstreamMode::UdpOnly { .. } => f.write_str("UdpOnly"),
            ProxyUpstreamMode::TcpAndUdp { .. } => f.write_str("TcpAndUdp"),
        }
    }
}

pub struct ProxyUpstream {
    context: SharedContext,
    ns: Address,
    mode: ProxyUpstreamMode,
}

impl ProxyUpstream {
    pub async fn new(context: SharedContext, ns: Address) -> ProxyUpstream {
        let mode = match context.config().mode {
            Mode::TcpOnly => ProxyUpstreamMode::TcpOnly {
                balancer: PlainPingBalancer::new(context.clone(), ServerType::Tcp).await,
            },
            Mode::UdpOnly => ProxyUpstreamMode::UdpOnly {
                balancer: PlainPingBalancer::new(context.clone(), ServerType::Udp).await,
            },
            Mode::TcpAndUdp => ProxyUpstreamMode::TcpAndUdp {
                tcp_balancer: PlainPingBalancer::new(context.clone(), ServerType::Tcp).await,
                udp_balancer: PlainPingBalancer::new(context.clone(), ServerType::Udp).await,
            },
        };

        ProxyUpstream { context, ns, mode }
    }

    async fn tcp_lookup(&self, svr_cfg: &ServerConfig, query: &Query) -> io::Result<Message> {
        trace!(
            "DNS TCP proxied query {:?} via {} to {}",
            query,
            svr_cfg.addr(),
            self.ns
        );
        let mut stream = ProxyStream::connect_proxied(self.context.clone(), svr_cfg, &self.ns).await?;
        stream_lookup(query, &mut stream).await
    }

    async fn udp_lookup(&self, svr_cfg: &ServerConfig, query: &Query) -> io::Result<Message> {
        let context = &self.context;

        trace!(
            "DNS UDP proxied query {:?} via {} to {}",
            query,
            svr_cfg.addr(),
            self.ns
        );

        let client = UdpServerClient::new(context, svr_cfg).await?;

        let message = generate_query_message(query);
        let send_buf = message.to_vec()?;

        client.send_to(context, &self.ns, &send_buf).await?;

        let (_, recv_buf) = client.recv_from(context).await?;
        Message::from_vec(&recv_buf).map_err(From::from)
    }
}

impl Debug for ProxyUpstream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProxyUpstream").field("ns", &self.ns).finish()
    }
}

impl Display for ProxyUpstream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.mode {
            ProxyUpstreamMode::TcpOnly { .. } => write!(f, "tcp://{}", self.ns),
            ProxyUpstreamMode::UdpOnly { .. } => write!(f, "udp://{}", self.ns),
            ProxyUpstreamMode::TcpAndUdp { .. } => write!(f, "tcp+udp://{}", self.ns),
        }
    }
}

#[async_trait]
impl Upstream for ProxyUpstream {
    async fn lookup(&self, _context: &Context, query: &Query) -> io::Result<Message> {
        match self.mode {
            ProxyUpstreamMode::TcpOnly { ref balancer } => {
                let svr_cfg = balancer.pick_server();
                self.tcp_lookup(svr_cfg.server_config(), query).await
            }
            ProxyUpstreamMode::UdpOnly { ref balancer } => {
                let svr_cfg = balancer.pick_server();
                self.udp_lookup(svr_cfg.server_config(), query).await
            }
            ProxyUpstreamMode::TcpAndUdp {
                ref tcp_balancer,
                ref udp_balancer,
            } => {
                let udp_svr_cfg = udp_balancer.pick_server();

                match time::timeout(
                    Duration::from_secs(2),
                    self.udp_lookup(udp_svr_cfg.server_config(), query),
                )
                .await
                {
                    Ok(Ok(message)) => {
                        trace!("ProxyUpstream {} TCP query answer, {:?}", self.ns, message);
                        Ok(message)
                    }
                    Ok(Err(..)) | Err(..) => {
                        trace!(
                            "ProxyUpstream {} UDP query failed, continue with TCP query, {:?}",
                            self.ns,
                            query
                        );

                        let tcp_svr_cfg = tcp_balancer.pick_server();
                        self.tcp_lookup(tcp_svr_cfg.server_config(), query).await
                    }
                }
            }
        }
    }
}

#[cfg(unix)]
#[derive(Debug)]
pub struct UnixSocketUpstream {
    pub path: PathBuf,
}

#[cfg(unix)]
#[async_trait]
impl Upstream for UnixSocketUpstream {
    async fn lookup(&self, _context: &Context, query: &Query) -> io::Result<Message> {
        let mut stream = UnixStream::connect(&self.path).await?;
        stream_lookup(query, &mut stream).await
    }
}
<commit_msg>Fixed remote query log<commit_after>#[cfg(unix)]
use std::path::PathBuf;
use std::{
    fmt::{self, Debug, Display},
    io,
    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
    time::Duration,
};

use async_trait::async_trait;
use byteorder::{BigEndian, ByteOrder};
use bytes::{BufMut, BytesMut};
use log::trace;
use rand::Rng;
#[cfg(unix)]
use tokio::net::UnixStream;
use tokio::{
    io::{AsyncReadExt, AsyncWriteExt},
    time,
};
use trust_dns_proto::{
    op::{Message, Query},
    rr::{DNSClass, Name, RData, RecordType},
};

use crate::{
    config::{Config, LocalDnsAddr, Mode, ServerConfig},
    context::{Context, SharedContext},
    relay::{
        loadbalancing::server::{PlainPingBalancer, ServerType},
        socks5::Address,
        sys::{create_outbound_udp_socket, tcp_stream_connect},
        tcprelay::ProxyStream,
        udprelay::client::ServerClient as UdpServerClient,
    },
};

#[derive(Debug)]
pub enum LocalUpstream {
    TcpAndUdp(TcpUpstream, UdpUpstream),
    #[cfg(unix)]
    UnixSocket(UnixSocketUpstream),
}

impl Display for LocalUpstream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            LocalUpstream::TcpAndUdp(ref t, ..) => write!(f, "tcp+udp://{}", t.server),
            #[cfg(unix)]
            LocalUpstream::UnixSocket(ref u) => write!(f, "unix://{}", u.path.display()),
        }
    }
}

impl LocalUpstream {
    pub fn new(config: &Config) -> LocalUpstream {
        match config.local_dns_addr {
            Some(LocalDnsAddr::SocketAddr(ns)) => {
                LocalUpstream::TcpAndUdp(TcpUpstream { server: ns }, UdpUpstream { server: ns })
            }
            #[cfg(unix)]
            Some(LocalDnsAddr::UnixSocketAddr(ref p)) => {
                LocalUpstream::UnixSocket(UnixSocketUpstream { path: p.clone() })
            }
            None => panic!("LocalUpstream requires config.local_dns_addr"),
        }
    }

    pub async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message> {
        match self {
            LocalUpstream::TcpAndUdp(tcp, udp) => {
                // UDP than TCP.
                // Because UDP should always be faster than TCP.

                match time::timeout(Duration::from_secs(2), udp.lookup(context, query)).await {
                    Ok(Ok(message)) => Ok(message),
                    Ok(Err(..)) | Err(..) => {
                        trace!(
                            "LocalUpstream {} UDP query failed, continue with TCP query, {:?}",
                            udp.server,
                            query
                        );

                        tcp.lookup(context, query).await
                    }
                }
            }
            #[cfg(unix)]
            LocalUpstream::UnixSocket(upstream) => upstream.lookup(context, query).await,
        }
    }

    pub async fn lookup_ip(&self, context: &Context, host: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
        let mut name = Name::from_utf8(host)?;
        name.set_fqdn(true);

        let mut queryv4 = Query::new();
        queryv4.set_query_class(DNSClass::IN);
        queryv4.set_name(name);

        let mut queryv6 = queryv4.clone();
        queryv4.set_query_type(RecordType::A);
        queryv6.set_query_type(RecordType::AAAA);

        let (responsev4, responsev6) =
            tokio::try_join!(self.lookup(context, &queryv4), self.lookup(context, &queryv6))?;

        macro_rules! parse {
            ($response:expr) => {
                $response.answers().iter().filter_map(|rec| match rec.rdata() {
                    RData::A(ref ip) => Some(SocketAddr::new(IpAddr::V4(ip.clone()), port)),
                    RData::AAAA(ref ip) => Some(SocketAddr::new(IpAddr::V6(ip.clone()), port)),
                    _ => None,
                })
            };
        }
        Ok(parse!(responsev4).chain(parse!(responsev6)).collect())
    }
}

#[async_trait]
pub trait Upstream {
    async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message>;
}

fn generate_query_message(query: &Query) -> Message {
    let mut message = Message::new();
    message.set_id(rand::thread_rng().gen());
    message.set_recursion_desired(true);
    message.add_query(query.clone());
    message
}

pub async fn read_message<T: AsyncReadExt + Unpin>(stream: &mut T) -> io::Result<Message> {
    let mut res_buffer = [0; 2];
    stream.read_exact(&mut res_buffer).await?;

    let size = BigEndian::read_u16(&res_buffer) as usize;
    let mut res_buffer = vec![0; size];
    stream.read_exact(&mut res_buffer).await?;

    Ok(Message::from_vec(&res_buffer)?)
}

pub async fn write_message<T: AsyncWriteExt + Unpin>(stream: &mut T, message: &Message) -> io::Result<()> {
    let req_buffer = message.to_vec()?;
    let size = req_buffer.len();

    let mut send_buffer = BytesMut::with_capacity(2 + size);
    send_buffer.put_u16(size as u16);
    send_buffer.put_slice(&req_buffer);

    stream.write_all(&send_buffer).await
}

async fn stream_lookup<T>(query: &Query, stream: &mut T) -> io::Result<Message>
where
    T: AsyncReadExt + AsyncWriteExt + Unpin,
{
    write_message(stream, &generate_query_message(query)).await?;
    read_message(stream).await
}

pub struct UdpUpstream {
    pub server: SocketAddr,
}

impl Debug for UdpUpstream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("UdpUpstream").field("ns", &self.server).finish()
    }
}

#[async_trait]
impl Upstream for UdpUpstream {
    async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message> {
        // TODO: Reuse UdpSocket for sending queries

        trace!("DNS local UDP query {:?} to {}", query, self.server);

        let local_addr = SocketAddr::new(
            match self.server {
                SocketAddr::V4(..) => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
                SocketAddr::V6(..) => IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
            },
            0,
        );
        let socket = create_outbound_udp_socket(&local_addr, context.config()).await?;

        socket.connect(self.server).await?;
        socket.send(&generate_query_message(query).to_vec()?).await?;
        let mut response = vec![0; 512];
        let len = socket.recv(&mut response).await?;
        Ok(Message::from_vec(&response[..len])?)
    }
}

#[derive(Debug)]
pub struct TcpUpstream {
    pub server: SocketAddr,
}

#[async_trait]
impl Upstream for TcpUpstream {
    async fn lookup(&self, context: &Context, query: &Query) -> io::Result<Message> {
        // TODO: Reuse UdpSocket for sending queries

        trace!("DNS local TCP query {:?} to {}", query, self.server);

        let mut stream = tcp_stream_connect(&self.server, context.config()).await?;
        stream_lookup(query, &mut stream).await
    }
}

enum ProxyUpstreamMode {
    TcpOnly {
        balancer: PlainPingBalancer,
    },
    UdpOnly {
        balancer: PlainPingBalancer,
    },
    TcpAndUdp {
        tcp_balancer: PlainPingBalancer,
        udp_balancer: PlainPingBalancer,
    },
}

impl Debug for ProxyUpstreamMode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ProxyUpstreamMode::TcpOnly { .. } => f.write_str("TcpOnly"),
            ProxyUpstreamMode::UdpOnly { .. } => f.write_str("UdpOnly"),
            ProxyUpstreamMode::TcpAndUdp { .. } => f.write_str("TcpAndUdp"),
        }
    }
}

pub struct ProxyUpstream {
    context: SharedContext,
    ns: Address,
    mode: ProxyUpstreamMode,
}

impl ProxyUpstream {
    pub async fn new(context: SharedContext, ns: Address) -> ProxyUpstream {
        let mode = match context.config().mode {
            Mode::TcpOnly => ProxyUpstreamMode::TcpOnly {
                balancer: PlainPingBalancer::new(context.clone(), ServerType::Tcp).await,
            },
            Mode::UdpOnly => ProxyUpstreamMode::UdpOnly {
                balancer: PlainPingBalancer::new(context.clone(), ServerType::Udp).await,
            },
            Mode::TcpAndUdp => ProxyUpstreamMode::TcpAndUdp {
                tcp_balancer: PlainPingBalancer::new(context.clone(), ServerType::Tcp).await,
                udp_balancer: PlainPingBalancer::new(context.clone(), ServerType::Udp).await,
            },
        };

        ProxyUpstream { context, ns, mode }
    }

    async fn tcp_lookup(&self, svr_cfg: &ServerConfig, query: &Query) -> io::Result<Message> {
        trace!(
            "DNS TCP proxied query {:?} via {} to {}",
            query,
            svr_cfg.addr(),
            self.ns
        );
        let mut stream = ProxyStream::connect_proxied(self.context.clone(), svr_cfg, &self.ns).await?;
        stream_lookup(query, &mut stream).await
    }

    async fn udp_lookup(&self, svr_cfg: &ServerConfig, query: &Query) -> io::Result<Message> {
        let context = &self.context;

        trace!(
            "DNS UDP proxied query {:?} via {} to {}",
            query,
            svr_cfg.addr(),
            self.ns
        );

        let client = UdpServerClient::new(context, svr_cfg).await?;

        let message = generate_query_message(query);
        let send_buf = message.to_vec()?;

        client.send_to(context, &self.ns, &send_buf).await?;

        let (_, recv_buf) = client.recv_from(context).await?;
        Message::from_vec(&recv_buf).map_err(From::from)
    }
}

impl Debug for ProxyUpstream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProxyUpstream").field("ns", &self.ns).finish()
    }
}

impl Display for ProxyUpstream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.mode {
            ProxyUpstreamMode::TcpOnly { .. } => write!(f, "tcp://{}", self.ns),
            ProxyUpstreamMode::UdpOnly { .. } => write!(f, "udp://{}", self.ns),
            ProxyUpstreamMode::TcpAndUdp { .. } => write!(f, "tcp+udp://{}", self.ns),
        }
    }
}

#[async_trait]
impl Upstream for ProxyUpstream {
    async fn lookup(&self, _context: &Context, query: &Query) -> io::Result<Message> {
        match self.mode {
            ProxyUpstreamMode::TcpOnly { ref balancer } => {
                let svr_cfg = balancer.pick_server();
                self.tcp_lookup(svr_cfg.server_config(), query).await
            }
            ProxyUpstreamMode::UdpOnly { ref balancer } => {
                let svr_cfg = balancer.pick_server();
                self.udp_lookup(svr_cfg.server_config(), query).await
            }
            ProxyUpstreamMode::TcpAndUdp {
                ref tcp_balancer,
                ref udp_balancer,
            } => {
                let udp_svr_cfg = udp_balancer.pick_server();

                match time::timeout(
                    Duration::from_secs(2),
                    self.udp_lookup(udp_svr_cfg.server_config(), query),
                )
                .await
                {
                    Ok(Ok(message)) => {
                        trace!("ProxyUpstream {} UDP query answer, {:?}", self.ns, message);
                        Ok(message)
                    }
                    Ok(Err(..)) | Err(..) => {
                        trace!(
                            "ProxyUpstream {} UDP query failed, continue with TCP query, {:?}",
                            self.ns,
                            query
                        );

                        let tcp_svr_cfg = tcp_balancer.pick_server();
                        self.tcp_lookup(tcp_svr_cfg.server_config(), query).await
                    }
                }
            }
        }
    }
}

#[cfg(unix)]
#[derive(Debug)]
pub struct UnixSocketUpstream {
    pub path: PathBuf,
}

#[cfg(unix)]
#[async_trait]
impl Upstream for UnixSocketUpstream {
    async fn lookup(&self, _context: &Context, query: &Query) -> io::Result<Message> {
        let mut stream = UnixStream::connect(&self.path).await?;
        stream_lookup(query, &mut stream).await
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::{util::get_fragment_filename, ModuleMetadata};
use graphql_ir::{
    associated_data_impl, Directive, FragmentDefinition, OperationDefinition, Program, Selection,
    Transformed, Transformer,
};
use intern::string_key::{Intern, StringKey, StringKeyMap};
use itertools::Itertools;
use schema::{Schema, TypeReference};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RelayDataDrivenDependencyMetadata {
    pub direct_dependencies: Option<Vec<(StringKey, StringKey)>>,
    // always None for fragments
    pub indirect_dependencies: Option<Vec<(StringKey, StringKey)>>,
}
associated_data_impl!(RelayDataDrivenDependencyMetadata);

pub fn generate_data_driven_dependency_metadata(program: &Program) -> Program {
    let mut transformer = GenerateDataDrivenDependencyMetadata::new(program);
    transformer
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct GenerateDataDrivenDependencyMetadata<'s> {
    pub program: &'s Program,
    cache: StringKeyMap<Option<ModuleEntries>>,
}

impl<'s> GenerateDataDrivenDependencyMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateDataDrivenDependencyMetadata {
            program,
            cache: Default::default(),
        }
    }

    fn get_direct_module_entries_for_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Option<&ModuleEntries> {
        let cache_key = fragment.name.item;
        #[allow(clippy::map_entry)]
        if !self.cache.contains_key(&cache_key) {
            let entries = self.extract_module_entries_from_selections(
                TypeReference::Named(fragment.type_condition),
                &fragment.selections,
                ModuleEntriesKind::Direct,
            );
            self.cache.insert(cache_key, entries);
        }
        self.cache.get(&cache_key).and_then(|v| v.as_ref())
    }

    fn extract_module_entries_from_selections(
        &mut self,
        type_: TypeReference,
        selections: &[Selection],
        kind: ModuleEntriesKind,
    ) -> Option<ModuleEntries> {
        let mut processing_queue: Vec<ProcessingItem<'_>> = vec![ProcessingItem {
            plural: false,
            parent_type: type_,
            selections,
        }];

        let mut module_entries: ModuleEntries = Default::default();

        while let Some(processing_item) = processing_queue.pop() {
            for selection in processing_item.selections {
                match selection {
                    Selection::ScalarField(_) => {}
                    Selection::FragmentSpread(spread) => {
                        if kind == ModuleEntriesKind::Direct {
                            continue;
                        }
                        let fragment = self.program.fragment(spread.fragment.item)?;
                        if let Some(fragment_module_entries) =
                            self.get_direct_module_entries_for_fragment(fragment)
                        {
                            for (id, entry) in fragment_module_entries {
                                module_entries
                                    .entry(*id)
                                    .and_modify(|module_entry| {
                                        module_entry.branches.extend(entry.branches.iter())
                                    })
                                    .or_insert_with(|| entry.clone());
                            }
                        }
                    }
                    Selection::LinkedField(linked_filed) => {
                        let field_type = &self
                            .program
                            .schema
                            .field(linked_filed.definition.item)
                            .type_;
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural || field_type.is_list(),
                            parent_type: field_type.clone(),
                            selections: &linked_filed.selections,
                        });
                    }
                    Selection::InlineFragment(inline_fragment) => {
                        let parent_type = match inline_fragment.type_condition {
                            Some(type_) => TypeReference::Named(type_),
                            None => processing_item.parent_type.clone(),
                        };
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural,
                            parent_type,
                            selections: &inline_fragment.selections,
                        });
                        if kind == ModuleEntriesKind::Indirect {
                            continue;
                        }
                        if let Some(module_metadata) =
                            ModuleMetadata::find(&inline_fragment.directives)
                        {
                            let id = module_metadata.module_id;
                            let component = module_metadata.module_name;

                            let fragment_spread = inline_fragment
                                .selections
                                .iter()
                                .find(|item| matches!(item, Selection::FragmentSpread(_)));
                            // This is expected to be a fragment spread
                            let fragment_name = match fragment_spread {
                                Some(Selection::FragmentSpread(spread)) => spread.fragment.item,
                                _ => panic!("Expected to have a fragment spread"),
                            };

                            let type_name = self
                                .program
                                .schema
                                .get_type_name(processing_item.parent_type.inner());
                            module_entries
                                .entry(id)
                                .and_modify(|module_entry| {
                                    module_entry.branches.insert(
                                        type_name,
                                        Branch {
                                            component,
                                            fragment: get_fragment_filename(fragment_name),
                                        },
                                    );
                                })
                                .or_insert(ModuleEntry {
                                    branches: {
                                        let mut map = StringKeyMap::default();
                                        map.insert(
                                            type_name,
                                            Branch {
                                                component,
                                                fragment: get_fragment_filename(fragment_name),
                                            },
                                        );
                                        map
                                    },
                                    plural: processing_item.plural,
                                });
                        }
                    }
                    Selection::Condition(condition) => {
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural,
                            parent_type: processing_item.parent_type.clone(),
                            selections: &condition.selections,
                        });
                    }
                }
            }
        }

        if !module_entries.is_empty() {
            Some(module_entries)
        } else {
            None
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Branch {
    component: StringKey,
    fragment: StringKey,
}

type ModuleEntries = StringKeyMap<ModuleEntry>;

#[derive(Debug, Clone)]
struct ModuleEntry {
    branches: StringKeyMap<Branch>,
    plural: bool,
}
#[derive(Debug, PartialEq, Eq)]

enum ModuleEntriesKind {
    Direct,
    Indirect,
}

#[derive(Debug)]
struct ProcessingItem<'a> {
    plural: bool,
    parent_type: TypeReference,
    selections: &'a [Selection],
}

impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> {
    const NAME: &'static str = "GenerateDataDrivenDependencyMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        let indirect_module_entries = self.extract_module_entries_from_selections(
            TypeReference::Named(operation.type_),
            &operation.selections,
            ModuleEntriesKind::Indirect,
        );
        let direct_module_entries = self.extract_module_entries_from_selections(
            TypeReference::Named(operation.type_),
            &operation.selections,
            ModuleEntriesKind::Direct,
        );
        if direct_module_entries.is_some() || indirect_module_entries.is_some() {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(operation.directives.len() + 1);
            next_directives.extend(operation.directives.iter().cloned());
            next_directives.push(
                RelayDataDrivenDependencyMetadata {
                    direct_dependencies: direct_module_entries
                        .as_ref()
                        .map(get_metadata_from_module_entries),
                    indirect_dependencies: indirect_module_entries
                        .as_ref()
                        .map(get_metadata_from_module_entries),
                }
                .into(),
            );
            Transformed::Replace(OperationDefinition {
                directives: next_directives,
                ..operation.clone()
            })
        } else {
            Transformed::Keep
        }
    }

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        if let Some(module_entries) = self.get_direct_module_entries_for_fragment(fragment) {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(fragment.directives.len() + 1);
            next_directives.extend(fragment.directives.iter().cloned());
            next_directives.push(
                RelayDataDrivenDependencyMetadata {
                    direct_dependencies: Some(get_metadata_from_module_entries(module_entries)),
                    indirect_dependencies: None,
                }
                .into(),
            );
            Transformed::Replace(FragmentDefinition {
                directives: next_directives,
                ..fragment.clone()
            })
        } else {
            Transformed::Keep
        }
    }
}

fn get_metadata_from_module_entries(module_entries: &ModuleEntries) -> Vec<(StringKey, StringKey)> {
    module_entries
        .iter()
        .map(|(key, entry)| {
            (
                *key,
                format!(
                    "{{\"branches\":{{{}}},\"plural\":{}}}",
                    entry
                        .branches
                        .iter()
                        .sorted_unstable_by(|a, b| a.0.cmp(b.0))
                        .map(|(id, branch)| format!(
                            "\"{}\":{{\"component\":\"{}\",\"fragment\":\"{}\"}}",
                            id, branch.component, branch.fragment
                        ))
                        .join(","),
                    entry.plural,
                )
                .intern(),
            )
        })
        .sorted_unstable_by(|a, b| a.0.cmp(&b.0))
        .collect()
}
<commit_msg>skip interning RelayDataDrivenDependencyMetadata values<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::{util::get_fragment_filename, ModuleMetadata};
use graphql_ir::{
    associated_data_impl, Directive, FragmentDefinition, OperationDefinition, Program, Selection,
    Transformed, Transformer,
};
use intern::string_key::{StringKey, StringKeyMap};
use itertools::Itertools;
use schema::{Schema, TypeReference};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RelayDataDrivenDependencyMetadata {
    pub direct_dependencies: Option<Vec<(StringKey, String)>>,
    // always None for fragments
    pub indirect_dependencies: Option<Vec<(StringKey, String)>>,
}
associated_data_impl!(RelayDataDrivenDependencyMetadata);

pub fn generate_data_driven_dependency_metadata(program: &Program) -> Program {
    let mut transformer = GenerateDataDrivenDependencyMetadata::new(program);
    transformer
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct GenerateDataDrivenDependencyMetadata<'s> {
    pub program: &'s Program,
    cache: StringKeyMap<Option<ModuleEntries>>,
}

impl<'s> GenerateDataDrivenDependencyMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateDataDrivenDependencyMetadata {
            program,
            cache: Default::default(),
        }
    }

    fn get_direct_module_entries_for_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Option<&ModuleEntries> {
        let cache_key = fragment.name.item;
        #[allow(clippy::map_entry)]
        if !self.cache.contains_key(&cache_key) {
            let entries = self.extract_module_entries_from_selections(
                TypeReference::Named(fragment.type_condition),
                &fragment.selections,
                ModuleEntriesKind::Direct,
            );
            self.cache.insert(cache_key, entries);
        }
        self.cache.get(&cache_key).and_then(|v| v.as_ref())
    }

    fn extract_module_entries_from_selections(
        &mut self,
        type_: TypeReference,
        selections: &[Selection],
        kind: ModuleEntriesKind,
    ) -> Option<ModuleEntries> {
        let mut processing_queue: Vec<ProcessingItem<'_>> = vec![ProcessingItem {
            plural: false,
            parent_type: type_,
            selections,
        }];

        let mut module_entries: ModuleEntries = Default::default();

        while let Some(processing_item) = processing_queue.pop() {
            for selection in processing_item.selections {
                match selection {
                    Selection::ScalarField(_) => {}
                    Selection::FragmentSpread(spread) => {
                        if kind == ModuleEntriesKind::Direct {
                            continue;
                        }
                        let fragment = self.program.fragment(spread.fragment.item)?;
                        if let Some(fragment_module_entries) =
                            self.get_direct_module_entries_for_fragment(fragment)
                        {
                            for (id, entry) in fragment_module_entries {
                                module_entries
                                    .entry(*id)
                                    .and_modify(|module_entry| {
                                        module_entry.branches.extend(entry.branches.iter())
                                    })
                                    .or_insert_with(|| entry.clone());
                            }
                        }
                    }
                    Selection::LinkedField(linked_filed) => {
                        let field_type = &self
                            .program
                            .schema
                            .field(linked_filed.definition.item)
                            .type_;
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural || field_type.is_list(),
                            parent_type: field_type.clone(),
                            selections: &linked_filed.selections,
                        });
                    }
                    Selection::InlineFragment(inline_fragment) => {
                        let parent_type = match inline_fragment.type_condition {
                            Some(type_) => TypeReference::Named(type_),
                            None => processing_item.parent_type.clone(),
                        };
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural,
                            parent_type,
                            selections: &inline_fragment.selections,
                        });
                        if kind == ModuleEntriesKind::Indirect {
                            continue;
                        }
                        if let Some(module_metadata) =
                            ModuleMetadata::find(&inline_fragment.directives)
                        {
                            let id = module_metadata.module_id;
                            let component = module_metadata.module_name;

                            let fragment_spread = inline_fragment
                                .selections
                                .iter()
                                .find(|item| matches!(item, Selection::FragmentSpread(_)));
                            // This is expected to be a fragment spread
                            let fragment_name = match fragment_spread {
                                Some(Selection::FragmentSpread(spread)) => spread.fragment.item,
                                _ => panic!("Expected to have a fragment spread"),
                            };

                            let type_name = self
                                .program
                                .schema
                                .get_type_name(processing_item.parent_type.inner());
                            module_entries
                                .entry(id)
                                .and_modify(|module_entry| {
                                    module_entry.branches.insert(
                                        type_name,
                                        Branch {
                                            component,
                                            fragment: get_fragment_filename(fragment_name),
                                        },
                                    );
                                })
                                .or_insert(ModuleEntry {
                                    branches: {
                                        let mut map = StringKeyMap::default();
                                        map.insert(
                                            type_name,
                                            Branch {
                                                component,
                                                fragment: get_fragment_filename(fragment_name),
                                            },
                                        );
                                        map
                                    },
                                    plural: processing_item.plural,
                                });
                        }
                    }
                    Selection::Condition(condition) => {
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural,
                            parent_type: processing_item.parent_type.clone(),
                            selections: &condition.selections,
                        });
                    }
                }
            }
        }

        if !module_entries.is_empty() {
            Some(module_entries)
        } else {
            None
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Branch {
    component: StringKey,
    fragment: StringKey,
}

type ModuleEntries = StringKeyMap<ModuleEntry>;

#[derive(Debug, Clone)]
struct ModuleEntry {
    branches: StringKeyMap<Branch>,
    plural: bool,
}
#[derive(Debug, PartialEq, Eq)]

enum ModuleEntriesKind {
    Direct,
    Indirect,
}

#[derive(Debug)]
struct ProcessingItem<'a> {
    plural: bool,
    parent_type: TypeReference,
    selections: &'a [Selection],
}

impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> {
    const NAME: &'static str = "GenerateDataDrivenDependencyMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        let indirect_module_entries = self.extract_module_entries_from_selections(
            TypeReference::Named(operation.type_),
            &operation.selections,
            ModuleEntriesKind::Indirect,
        );
        let direct_module_entries = self.extract_module_entries_from_selections(
            TypeReference::Named(operation.type_),
            &operation.selections,
            ModuleEntriesKind::Direct,
        );
        if direct_module_entries.is_some() || indirect_module_entries.is_some() {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(operation.directives.len() + 1);
            next_directives.extend(operation.directives.iter().cloned());
            next_directives.push(
                RelayDataDrivenDependencyMetadata {
                    direct_dependencies: direct_module_entries
                        .as_ref()
                        .map(get_metadata_from_module_entries),
                    indirect_dependencies: indirect_module_entries
                        .as_ref()
                        .map(get_metadata_from_module_entries),
                }
                .into(),
            );
            Transformed::Replace(OperationDefinition {
                directives: next_directives,
                ..operation.clone()
            })
        } else {
            Transformed::Keep
        }
    }

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        if let Some(module_entries) = self.get_direct_module_entries_for_fragment(fragment) {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(fragment.directives.len() + 1);
            next_directives.extend(fragment.directives.iter().cloned());
            next_directives.push(
                RelayDataDrivenDependencyMetadata {
                    direct_dependencies: Some(get_metadata_from_module_entries(module_entries)),
                    indirect_dependencies: None,
                }
                .into(),
            );
            Transformed::Replace(FragmentDefinition {
                directives: next_directives,
                ..fragment.clone()
            })
        } else {
            Transformed::Keep
        }
    }
}

fn get_metadata_from_module_entries(module_entries: &ModuleEntries) -> Vec<(StringKey, String)> {
    module_entries
        .iter()
        .map(|(key, entry)| {
            (
                *key,
                format!(
                    "{{\"branches\":{{{}}},\"plural\":{}}}",
                    entry
                        .branches
                        .iter()
                        .sorted_unstable_by(|a, b| a.0.cmp(b.0))
                        .map(|(id, branch)| format!(
                            "\"{}\":{{\"component\":\"{}\",\"fragment\":\"{}\"}}",
                            id, branch.component, branch.fragment
                        ))
                        .join(","),
                    entry.plural,
                ),
            )
        })
        .sorted_unstable_by(|a, b| a.0.cmp(&b.0))
        .collect()
}
<|endoftext|>


<commit_before>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ServerNameBox, ServerSigningKeyId, UserId};
use ruma_serde::Outgoing;
use serde::Serialize;

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a UserId,

    /// The Matrix ID of the invitee.
    pub mxid: &'a UserId,

    /// The state key of the `m.third_party_invite` event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

impl<'a> ThirdPartySigned<'a> {
    /// Creates a new `ThirdPartySigned` from the given sender and invitee user IDs, state key token
    /// and signatures.
    pub fn new(
        sender: &'a UserId,
        mxid: &'a UserId,
        token: &'a str,
        signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
    ) -> Self {
        Self { sender, mxid, token, signatures }
    }
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, PartialEq, Outgoing, Serialize)]
#[incoming_derive(PartialEq)]
pub struct Invite3pid<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}
<commit_msg>client-api: Make r0::membership::Invite3pid non-exhaustive<commit_after>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ServerNameBox, ServerSigningKeyId, UserId};
use ruma_serde::Outgoing;
use serde::Serialize;

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a UserId,

    /// The Matrix ID of the invitee.
    pub mxid: &'a UserId,

    /// The state key of the `m.third_party_invite` event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

impl<'a> ThirdPartySigned<'a> {
    /// Creates a new `ThirdPartySigned` from the given sender and invitee user IDs, state key token
    /// and signatures.
    pub fn new(
        sender: &'a UserId,
        mxid: &'a UserId,
        token: &'a str,
        signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
    ) -> Self {
        Self { sender, mxid, token, signatures }
    }
}

/// Represents third party IDs to invite to the room.
///
/// To create an instance of this type, first create a `Invite3pidInit` and convert it via
/// `Invite3pid::from` / `.into()`.
#[derive(Clone, Debug, PartialEq, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(PartialEq)]
pub struct Invite3pid<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}

/// Initial set of fields of `Invite3pid`.
///
/// This struct will not be updated even if additional fields are added to `Invite3pid` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
pub struct Invite3pidInit<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}

impl<'a> From<Invite3pidInit<'a>> for Invite3pid<'a> {
    fn from(init: Invite3pidInit<'a>) -> Self {
        let Invite3pidInit { id_server, id_access_token, medium, address } = init;
        Self { id_server, id_access_token, medium, address }
    }
}
<|endoftext|>