<commit_before>use std::ops;
use std::num::ToPrimitive;
use std::cmp::Ordering;
use std::iter::IntoIterator;

use index::Index;

#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum Value {
    Bool(bool),
    String(String),
    Float(f64),
    Tuple(Tuple),
    Relation(Relation),
}
pub type Tuple = Vec<Value>;
pub type Relation = Index<Vec<Value>>; // a set of tuples
pub type Id = String; // TODO use uuid?

impl Ord for Value {
    fn cmp(&self, other: &Value) -> Ordering {
        self.partial_cmp(other).unwrap() // TODO this will panic on NaN
    }
}

impl Eq for Value {} // TODO this is unsafe for NaN

impl ops::Index<usize> for Value {
    type Output = Value;

    fn index(&self, index: usize) -> &Value {
        match *self {
            Value::Tuple(ref tuple) => tuple.index(index),
            _ => panic!("Indexing a non-tuple value"),
        }
    }
}

impl ToString for Value {
    fn to_string(&self) -> String {
        match *self {
            Value::String(ref string) => string.clone(),
            _ => panic!("Stringifying a non-string value"),
        }
    }
}

impl ToPrimitive for Value {
    fn to_f64(&self) -> Option<f64> {
        match *self {
            Value::Float(ref float) => float.to_f64(),
            _ => None,
        }
    }
    fn to_i64(&self) -> Option<i64> {
        match *self {
            Value::Float(ref float) => float.to_i64(),
            _ => None,
        }
    }
    fn to_u64(&self) -> Option<u64> {
        match *self {
            Value::Float(ref float) => float.to_u64(),
            _ => None,
        }
    }
}

pub trait ToValue {
    fn to_value(self) -> Value;
}

pub trait ToTuple {
    fn to_tuple(self) -> Tuple;
}

impl ToTuple for Value {
    fn to_tuple(self) -> Tuple {
        match self {
            Value::Tuple(x) => x.clone(),
            _ => vec![self],
        }
    }
}

impl<'a> ToTuple for &'a Value {
    fn to_tuple(self) -> Tuple {
        match self {
            &Value::Tuple(ref x) => x.clone(),
            _ => vec![self.clone()],
        }
    }
}

pub trait ToRelation {
    fn to_relation(self) -> Relation;
}

impl ToValue for Value {
    fn to_value(self) -> Value {
        self
    }
}

impl ToValue for bool {
    fn to_value(self) -> Value {
        Value::Bool(self)
    }
}

impl<'a> ToValue for &'a str {
    fn to_value(self) -> Value {
        Value::String(self.to_string())
    }
}

impl ToValue for String {
    fn to_value(self) -> Value {
        Value::String(self)
    }
}

impl ToValue for f64 {
    fn to_value(self) -> Value {
        Value::Float(self)
    }
}

impl ToValue for i32 {
     fn to_value(self) -> Value {
        Value::Float(self as f64)
    }
}

impl ToValue for i64 {
     fn to_value(self) -> Value {
        Value::Float(self as f64)
    }
}

impl ToValue for Tuple {
    fn to_value(self) -> Value {
        Value::Tuple(self)
    }

}

impl ToValue for usize {
    fn to_value(self) -> Value {
        Value::Float(self.to_f64().unwrap())
    }
}

// impl<T: ToTuple> ToValue for T {
//     fn to_value(self) -> Value {
//         Value::Tuple(self.to_tuple())
//     }
// }

// impl<T: ToRelation> ToValue for T where T: !ToTuple {
//     fn to_value(self) -> Value {
//         Value::Relation(self.to_relation())
//     }
// }

impl<A: ToValue> ToTuple for (A,) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,) = self;
        vec![a.to_value()]
    }
}

impl<A: ToValue, B: ToValue> ToTuple for (A,B) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b) = self;
        vec![a.to_value(), b.to_value()]
    }
}

impl<A: ToValue, B: ToValue, C: ToValue> ToTuple for (A,B,C) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b,c) = self;
        vec![a.to_value(), b.to_value(), c.to_value()]
    }
}

impl<A: ToValue, B: ToValue, C: ToValue, D: ToValue> ToTuple for (A,B,C,D) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b,c,d) = self;
        vec![a.to_value(), b.to_value(), c.to_value(), d.to_value()]
    }
}

impl<A: ToValue, B: ToValue, C: ToValue, D: ToValue, E: ToValue> ToTuple for (A,B,C,D,E) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b,c,d,e) = self;
        vec![a.to_value(), b.to_value(), c.to_value(), d.to_value(), e.to_value()]
    }
}

impl<T: ToTuple> ToRelation for Vec<T> {
    fn to_relation(self) -> Relation {
        self.into_iter().map(|t| t.to_tuple()).collect()
    }
}
<commit_msg>Dont cover up errors<commit_after>use std::ops;
use std::num::ToPrimitive;
use std::cmp::Ordering;
use std::iter::IntoIterator;

use index::Index;

#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum Value {
    Bool(bool),
    String(String),
    Float(f64),
    Tuple(Tuple),
    Relation(Relation),
}
pub type Tuple = Vec<Value>;
pub type Relation = Index<Vec<Value>>; // a set of tuples
pub type Id = String; // TODO use uuid?

impl Ord for Value {
    fn cmp(&self, other: &Value) -> Ordering {
        self.partial_cmp(other).unwrap() // TODO this will panic on NaN
    }
}

impl Eq for Value {} // TODO this is unsafe for NaN

impl ops::Index<usize> for Value {
    type Output = Value;

    fn index(&self, index: usize) -> &Value {
        match *self {
            Value::Tuple(ref tuple) => tuple.index(index),
            _ => panic!("Indexing a non-tuple value"),
        }
    }
}

impl ToString for Value {
    fn to_string(&self) -> String {
        match *self {
            Value::String(ref string) => string.clone(),
            _ => panic!("Stringifying a non-string value"),
        }
    }
}

impl ToPrimitive for Value {
    fn to_f64(&self) -> Option<f64> {
        match *self {
            Value::Float(ref float) => float.to_f64(),
            _ => None,
        }
    }
    fn to_i64(&self) -> Option<i64> {
        match *self {
            Value::Float(ref float) => float.to_i64(),
            _ => None,
        }
    }
    fn to_u64(&self) -> Option<u64> {
        match *self {
            Value::Float(ref float) => float.to_u64(),
            _ => None,
        }
    }
}

pub trait ToValue {
    fn to_value(self) -> Value;
}

pub trait ToTuple {
    fn to_tuple(self) -> Tuple;
}

impl ToTuple for Value {
    fn to_tuple(self) -> Tuple {
        match self {
            Value::Tuple(x) => x.clone(),
            _ => vec![self],
        }
    }
}

impl<'a> ToTuple for &'a Value {
    fn to_tuple(self) -> Tuple {
        match self {
            &Value::Tuple(ref x) => x.clone(),
            other => panic!("Not a tuple: {:?}", other),
        }
    }
}

pub trait ToRelation {
    fn to_relation(self) -> Relation;
}

impl ToValue for Value {
    fn to_value(self) -> Value {
        self
    }
}

impl ToValue for bool {
    fn to_value(self) -> Value {
        Value::Bool(self)
    }
}

impl<'a> ToValue for &'a str {
    fn to_value(self) -> Value {
        Value::String(self.to_string())
    }
}

impl ToValue for String {
    fn to_value(self) -> Value {
        Value::String(self)
    }
}

impl ToValue for f64 {
    fn to_value(self) -> Value {
        Value::Float(self)
    }
}

impl ToValue for i32 {
     fn to_value(self) -> Value {
        Value::Float(self as f64)
    }
}

impl ToValue for i64 {
     fn to_value(self) -> Value {
        Value::Float(self as f64)
    }
}

impl ToValue for Tuple {
    fn to_value(self) -> Value {
        Value::Tuple(self)
    }

}

impl ToValue for usize {
    fn to_value(self) -> Value {
        Value::Float(self.to_f64().unwrap())
    }
}

// impl<T: ToTuple> ToValue for T {
//     fn to_value(self) -> Value {
//         Value::Tuple(self.to_tuple())
//     }
// }

// impl<T: ToRelation> ToValue for T where T: !ToTuple {
//     fn to_value(self) -> Value {
//         Value::Relation(self.to_relation())
//     }
// }

impl<A: ToValue> ToTuple for (A,) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,) = self;
        vec![a.to_value()]
    }
}

impl<A: ToValue, B: ToValue> ToTuple for (A,B) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b) = self;
        vec![a.to_value(), b.to_value()]
    }
}

impl<A: ToValue, B: ToValue, C: ToValue> ToTuple for (A,B,C) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b,c) = self;
        vec![a.to_value(), b.to_value(), c.to_value()]
    }
}

impl<A: ToValue, B: ToValue, C: ToValue, D: ToValue> ToTuple for (A,B,C,D) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b,c,d) = self;
        vec![a.to_value(), b.to_value(), c.to_value(), d.to_value()]
    }
}

impl<A: ToValue, B: ToValue, C: ToValue, D: ToValue, E: ToValue> ToTuple for (A,B,C,D,E) {
    fn to_tuple(self) -> Vec<Value> {
        let (a,b,c,d,e) = self;
        vec![a.to_value(), b.to_value(), c.to_value(), d.to_value(), e.to_value()]
    }
}

impl<T: ToTuple> ToRelation for Vec<T> {
    fn to_relation(self) -> Relation {
        self.into_iter().map(|t| t.to_tuple()).collect()
    }
}
<|endoftext|>


<commit_before>//! Renderer for function calls.

use hir::{HasSource, HirDisplay, Type};
use ide_db::SymbolKind;
use itertools::Itertools;
use syntax::ast::Fn;

use crate::{
    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
    render::{builder_ext::Params, RenderContext},
};

pub(crate) fn render_fn<'a>(
    ctx: RenderContext<'a>,
    import_to_add: Option<ImportEdit>,
    local_name: Option<String>,
    fn_: hir::Function,
) -> Option<CompletionItem> {
    let _p = profile::span("render_fn");
    Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
}

#[derive(Debug)]
struct FunctionRender<'a> {
    ctx: RenderContext<'a>,
    name: String,
    func: hir::Function,
    ast_node: Fn,
}

impl<'a> FunctionRender<'a> {
    fn new(
        ctx: RenderContext<'a>,
        local_name: Option<String>,
        fn_: hir::Function,
    ) -> Option<FunctionRender<'a>> {
        let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string());
        let ast_node = fn_.source(ctx.db())?.value;

        Some(FunctionRender { ctx, name, func: fn_, ast_node })
    }

    fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
        let params = self.params();
        let mut item = CompletionItem::new(
            CompletionKind::Reference,
            self.ctx.source_range(),
            self.name.clone(),
        );
        item.kind(self.kind())
            .set_documentation(self.ctx.docs(self.func))
            .set_deprecated(
                self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
            )
            .detail(self.detail())
            .add_call_parens(self.ctx.completion, self.name, params)
            .add_import(import_to_add);

        item.build()
    }

    fn detail(&self) -> String {
        let params = if let Some(self_param) = self.func.self_param(self.ctx.db()) {
            let params = self
                .func
                .assoc_fn_params(self.ctx.db())
                .into_iter()
                .skip(1) // skip the self param because we are manually handling that
                .map(|p| p.ty().display(self.ctx.db()).to_string());

            std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ")
        } else {
            let params = self
                .func
                .assoc_fn_params(self.ctx.db())
                .into_iter()
                .map(|p| p.ty().display(self.ctx.db()).to_string())
                .join(", ");
            params
        };

        let ret_ty = self.func.ret_type(self.ctx.db());
        let ret = if ret_ty.is_unit() {
            // Omit the `-> ()` for unit return types
            String::new()
        } else {
            format!(" -> {}", ret_ty.display(self.ctx.db()))
        };

        format!("fn({}){}", params, ret)
    }

    fn add_arg(&self, arg: &str, ty: &Type) -> String {
        if let Some(derefed_ty) = ty.remove_ref() {
            for (name, local) in self.ctx.completion.locals.iter() {
                if name == arg && local.ty(self.ctx.db()) == derefed_ty {
                    let mutability = if ty.is_mutable_reference() { "&mut " } else { "&" };
                    return format!("{}{}", mutability, arg);
                }
            }
        }
        arg.to_string()
    }

    fn params(&self) -> Params {
        let ast_params = match self.ast_node.param_list() {
            Some(it) => it,
            None => return Params::Named(Vec::new()),
        };

        let mut params_pats = Vec::new();
        let params_ty = if self.ctx.completion.dot_receiver.is_some() {
            self.func.method_params(self.ctx.db()).unwrap_or_default()
        } else {
            if let Some(s) = ast_params.self_param() {
                cov_mark::hit!(parens_for_method_call_as_assoc_fn);
                params_pats.push(Some(s.to_string()));
            }
            self.func.assoc_fn_params(self.ctx.db())
        };
        params_pats
            .extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string())));

        let params = params_pats
            .into_iter()
            .zip(params_ty)
            .flat_map(|(pat, param_ty)| {
                let pat = pat?;
                let name = pat;
                let arg = name.trim_start_matches("mut ").trim_start_matches('_');
                Some(self.add_arg(arg, param_ty.ty()))
            })
            .collect();
        Params::Named(params)
    }

    fn kind(&self) -> CompletionItemKind {
        if self.func.self_param(self.ctx.db()).is_some() {
            CompletionItemKind::Method
        } else {
            SymbolKind::Function.into()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        test_utils::{check_edit, check_edit_with_config, TEST_CONFIG},
        CompletionConfig,
    };

    #[test]
    fn inserts_parens_for_function_calls() {
        cov_mark::check!(inserts_parens_for_function_calls);
        check_edit(
            "no_args",
            r#"
fn no_args() {}
fn main() { no_$0 }
"#,
            r#"
fn no_args() {}
fn main() { no_args()$0 }
"#,
        );

        check_edit(
            "with_args",
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_$0 }
"#,
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_args(${1:x}, ${2:y})$0 }
"#,
        );

        check_edit(
            "foo",
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn bar(s: &S) { s.f$0 }
"#,
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn bar(s: &S) { s.foo()$0 }
"#,
        );

        check_edit(
            "foo",
            r#"
struct S {}
impl S {
    fn foo(&self, x: i32) {}
}
fn bar(s: &S) {
    s.f$0
}
"#,
            r#"
struct S {}
impl S {
    fn foo(&self, x: i32) {}
}
fn bar(s: &S) {
    s.foo(${1:x})$0
}
"#,
        );
    }

    #[test]
    fn parens_for_method_call_as_assoc_fn() {
        cov_mark::check!(parens_for_method_call_as_assoc_fn);
        check_edit(
            "foo",
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn main() { S::f$0 }
"#,
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn main() { S::foo(${1:&self})$0 }
"#,
        );
    }

    #[test]
    fn suppress_arg_snippets() {
        cov_mark::check!(suppress_arg_snippets);
        check_edit_with_config(
            CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG },
            "with_args",
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_$0 }
"#,
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_args($0) }
"#,
        );
    }

    #[test]
    fn strips_underscores_from_args() {
        check_edit(
            "foo",
            r#"
fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
fn main() { f$0 }
"#,
            r#"
fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
"#,
        );
    }

    #[test]
    fn insert_ref_when_matching_local_in_scope() {
        check_edit(
            "ref_arg",
            r#"
struct Foo {}
fn ref_arg(x: &Foo) {}
fn main() {
    let x = Foo {};
    ref_ar$0
}
"#,
            r#"
struct Foo {}
fn ref_arg(x: &Foo) {}
fn main() {
    let x = Foo {};
    ref_arg(${1:&x})$0
}
"#,
        );
    }

    #[test]
    fn insert_mut_ref_when_matching_local_in_scope() {
        check_edit(
            "ref_arg",
            r#"
struct Foo {}
fn ref_arg(x: &mut Foo) {}
fn main() {
    let x = Foo {};
    ref_ar$0
}
"#,
            r#"
struct Foo {}
fn ref_arg(x: &mut Foo) {}
fn main() {
    let x = Foo {};
    ref_arg(${1:&mut x})$0
}
"#,
        );
    }

    #[test]
    fn insert_ref_when_matching_local_in_scope_for_method() {
        check_edit(
            "apply_foo",
            r#"
struct Foo {}
struct Bar {}
impl Bar {
    fn apply_foo(&self, x: &Foo) {}
}

fn main() {
    let x = Foo {};
    let y = Bar {};
    y.$0
}
"#,
            r#"
struct Foo {}
struct Bar {}
impl Bar {
    fn apply_foo(&self, x: &Foo) {}
}

fn main() {
    let x = Foo {};
    let y = Bar {};
    y.apply_foo(${1:&x})$0
}
"#,
        );
    }

    #[test]
    fn trim_mut_keyword_in_func_completion() {
        check_edit(
            "take_mutably",
            r#"
fn take_mutably(mut x: &i32) {}

fn main() {
    take_m$0
}
"#,
            r#"
fn take_mutably(mut x: &i32) {}

fn main() {
    take_mutably(${1:x})$0
}
"#,
        );
    }
}
<commit_msg>add params_display and ty_display<commit_after>//! Renderer for function calls.

use hir::{HasSource, HirDisplay, Type};
use ide_db::SymbolKind;
use itertools::Itertools;
use syntax::ast::Fn;

use crate::{
    item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
    render::{builder_ext::Params, RenderContext},
};

pub(crate) fn render_fn<'a>(
    ctx: RenderContext<'a>,
    import_to_add: Option<ImportEdit>,
    local_name: Option<String>,
    fn_: hir::Function,
) -> Option<CompletionItem> {
    let _p = profile::span("render_fn");
    Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
}

#[derive(Debug)]
struct FunctionRender<'a> {
    ctx: RenderContext<'a>,
    name: String,
    func: hir::Function,
    ast_node: Fn,
}

impl<'a> FunctionRender<'a> {
    fn new(
        ctx: RenderContext<'a>,
        local_name: Option<String>,
        fn_: hir::Function,
    ) -> Option<FunctionRender<'a>> {
        let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string());
        let ast_node = fn_.source(ctx.db())?.value;

        Some(FunctionRender { ctx, name, func: fn_, ast_node })
    }

    fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
        let params = self.params();
        let mut item = CompletionItem::new(
            CompletionKind::Reference,
            self.ctx.source_range(),
            self.name.clone(),
        );
        item.kind(self.kind())
            .set_documentation(self.ctx.docs(self.func))
            .set_deprecated(
                self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
            )
            .detail(self.detail())
            .add_call_parens(self.ctx.completion, self.name, params)
            .add_import(import_to_add);

        item.build()
    }

    fn detail(&self) -> String {
        let ret_ty = self.func.ret_type(self.ctx.db());
        let ret = if ret_ty.is_unit() {
            // Omit the return type if it is the unit type
            String::new()
        } else {
            format!(" {}", self.ty_display())
        };

        format!("fn({}){}", self.params_display(), ret)
    }

    fn params_display(&self) -> String {
        if let Some(self_param) = self.func.self_param(self.ctx.db()) {
            let params = self
                .func
                .assoc_fn_params(self.ctx.db())
                .into_iter()
                .skip(1) // skip the self param because we are manually handling that
                .map(|p| p.ty().display(self.ctx.db()).to_string());

            std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ")
        } else {
            let params = self
                .func
                .assoc_fn_params(self.ctx.db())
                .into_iter()
                .map(|p| p.ty().display(self.ctx.db()).to_string())
                .join(", ");
            params
        }
    }

    fn ty_display(&self) -> String {
        let ret_ty = self.func.ret_type(self.ctx.db());

        format!("-> {}", ret_ty.display(self.ctx.db()))
    }

    fn add_arg(&self, arg: &str, ty: &Type) -> String {
        if let Some(derefed_ty) = ty.remove_ref() {
            for (name, local) in self.ctx.completion.locals.iter() {
                if name == arg && local.ty(self.ctx.db()) == derefed_ty {
                    let mutability = if ty.is_mutable_reference() { "&mut " } else { "&" };
                    return format!("{}{}", mutability, arg);
                }
            }
        }
        arg.to_string()
    }

    fn params(&self) -> Params {
        let ast_params = match self.ast_node.param_list() {
            Some(it) => it,
            None => return Params::Named(Vec::new()),
        };

        let mut params_pats = Vec::new();
        let params_ty = if self.ctx.completion.dot_receiver.is_some() {
            self.func.method_params(self.ctx.db()).unwrap_or_default()
        } else {
            if let Some(s) = ast_params.self_param() {
                cov_mark::hit!(parens_for_method_call_as_assoc_fn);
                params_pats.push(Some(s.to_string()));
            }
            self.func.assoc_fn_params(self.ctx.db())
        };
        params_pats
            .extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string())));

        let params = params_pats
            .into_iter()
            .zip(params_ty)
            .flat_map(|(pat, param_ty)| {
                let pat = pat?;
                let name = pat;
                let arg = name.trim_start_matches("mut ").trim_start_matches('_');
                Some(self.add_arg(arg, param_ty.ty()))
            })
            .collect();
        Params::Named(params)
    }

    fn kind(&self) -> CompletionItemKind {
        if self.func.self_param(self.ctx.db()).is_some() {
            CompletionItemKind::Method
        } else {
            SymbolKind::Function.into()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        test_utils::{check_edit, check_edit_with_config, TEST_CONFIG},
        CompletionConfig,
    };

    #[test]
    fn inserts_parens_for_function_calls() {
        cov_mark::check!(inserts_parens_for_function_calls);
        check_edit(
            "no_args",
            r#"
fn no_args() {}
fn main() { no_$0 }
"#,
            r#"
fn no_args() {}
fn main() { no_args()$0 }
"#,
        );

        check_edit(
            "with_args",
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_$0 }
"#,
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_args(${1:x}, ${2:y})$0 }
"#,
        );

        check_edit(
            "foo",
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn bar(s: &S) { s.f$0 }
"#,
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn bar(s: &S) { s.foo()$0 }
"#,
        );

        check_edit(
            "foo",
            r#"
struct S {}
impl S {
    fn foo(&self, x: i32) {}
}
fn bar(s: &S) {
    s.f$0
}
"#,
            r#"
struct S {}
impl S {
    fn foo(&self, x: i32) {}
}
fn bar(s: &S) {
    s.foo(${1:x})$0
}
"#,
        );
    }

    #[test]
    fn parens_for_method_call_as_assoc_fn() {
        cov_mark::check!(parens_for_method_call_as_assoc_fn);
        check_edit(
            "foo",
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn main() { S::f$0 }
"#,
            r#"
struct S;
impl S {
    fn foo(&self) {}
}
fn main() { S::foo(${1:&self})$0 }
"#,
        );
    }

    #[test]
    fn suppress_arg_snippets() {
        cov_mark::check!(suppress_arg_snippets);
        check_edit_with_config(
            CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG },
            "with_args",
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_$0 }
"#,
            r#"
fn with_args(x: i32, y: String) {}
fn main() { with_args($0) }
"#,
        );
    }

    #[test]
    fn strips_underscores_from_args() {
        check_edit(
            "foo",
            r#"
fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
fn main() { f$0 }
"#,
            r#"
fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
"#,
        );
    }

    #[test]
    fn insert_ref_when_matching_local_in_scope() {
        check_edit(
            "ref_arg",
            r#"
struct Foo {}
fn ref_arg(x: &Foo) {}
fn main() {
    let x = Foo {};
    ref_ar$0
}
"#,
            r#"
struct Foo {}
fn ref_arg(x: &Foo) {}
fn main() {
    let x = Foo {};
    ref_arg(${1:&x})$0
}
"#,
        );
    }

    #[test]
    fn insert_mut_ref_when_matching_local_in_scope() {
        check_edit(
            "ref_arg",
            r#"
struct Foo {}
fn ref_arg(x: &mut Foo) {}
fn main() {
    let x = Foo {};
    ref_ar$0
}
"#,
            r#"
struct Foo {}
fn ref_arg(x: &mut Foo) {}
fn main() {
    let x = Foo {};
    ref_arg(${1:&mut x})$0
}
"#,
        );
    }

    #[test]
    fn insert_ref_when_matching_local_in_scope_for_method() {
        check_edit(
            "apply_foo",
            r#"
struct Foo {}
struct Bar {}
impl Bar {
    fn apply_foo(&self, x: &Foo) {}
}

fn main() {
    let x = Foo {};
    let y = Bar {};
    y.$0
}
"#,
            r#"
struct Foo {}
struct Bar {}
impl Bar {
    fn apply_foo(&self, x: &Foo) {}
}

fn main() {
    let x = Foo {};
    let y = Bar {};
    y.apply_foo(${1:&x})$0
}
"#,
        );
    }

    #[test]
    fn trim_mut_keyword_in_func_completion() {
        check_edit(
            "take_mutably",
            r#"
fn take_mutably(mut x: &i32) {}

fn main() {
    take_m$0
}
"#,
            r#"
fn take_mutably(mut x: &i32) {}

fn main() {
    take_mutably(${1:x})$0
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018-2020 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2019-2021 François Laignel <fengalin@free.fr>
//
// Take a look at the license at the top of the repository in the LICENSE file.

use concurrent_queue::ConcurrentQueue;

use futures::channel::oneshot;
use futures::pin_mut;

use gio::glib::clone::Downgrade;
use gst::{gst_debug, gst_error, gst_trace, gst_warning};

use std::cell::RefCell;
use std::future::Future;
use std::panic;
use std::sync::mpsc as sync_mpsc;
use std::sync::{Arc, Condvar, Mutex, Weak};
use std::task::Poll;
use std::thread;
use std::time::{Duration, Instant};

use waker_fn::waker_fn;

use super::task::{SubTaskOutput, TaskId, TaskQueue};
use super::{CallOnDrop, JoinHandle, Reactor, Source};
use crate::runtime::RUNTIME_CAT;

thread_local! {
    static CURRENT_SCHEDULER: RefCell<Option<HandleWeak>> = RefCell::new(None);
}

#[derive(Debug)]
struct CleanUpOps(Arc<Source>);

#[derive(Debug)]
pub(super) struct Scheduler {
    context_name: Arc<str>,
    max_throttling: Duration,
    tasks: TaskQueue,
    cleanup_ops: ConcurrentQueue<CleanUpOps>,
    must_awake: Mutex<bool>,
    must_awake_cvar: Condvar,
}

impl Scheduler {
    pub const DUMMY_NAME: &'static str = "DUMMY";

    pub fn start(context_name: &str, max_throttling: Duration) -> Handle {
        // Name the thread so that it appears in panic messages.
        let thread = thread::Builder::new().name(context_name.to_string());

        let (handle_sender, handle_receiver) = sync_mpsc::channel();
        let (shutdown_sender, shutdown_receiver) = oneshot::channel();
        let context_name = Arc::from(context_name);
        let thread_ctx_name = Arc::clone(&context_name);
        let join = thread
            .spawn(move || {
                gst_debug!(
                    RUNTIME_CAT,
                    "Started Scheduler thread for Context {}",
                    thread_ctx_name
                );

                let handle = Scheduler::init(Arc::clone(&thread_ctx_name), max_throttling);
                let this = Arc::clone(&handle.0.scheduler);
                handle_sender.send(handle.clone()).unwrap();

                match this.block_on_priv(shutdown_receiver) {
                    Ok(_) => {
                        gst_debug!(
                            RUNTIME_CAT,
                            "Scheduler thread shut down for Context {}",
                            thread_ctx_name
                        );
                    }
                    Err(e) => {
                        gst_error!(
                            RUNTIME_CAT,
                            "Scheduler thread shut down due to an error within Context {}",
                            thread_ctx_name
                        );

                        // We are shutting down on our own initiative
                        if let Ok(mut shutdown) = handle.0.shutdown.lock() {
                            shutdown.clear();
                        }

                        panic::resume_unwind(e);
                    }
                }
            })
            .expect("Failed to spawn Scheduler thread");

        let handle = handle_receiver.recv().expect("Context thread init failed");
        handle.set_shutdown(shutdown_sender, join);

        handle
    }

    fn init(context_name: Arc<str>, max_throttling: Duration) -> Handle {
        let handle = CURRENT_SCHEDULER.with(|cur_scheduler| {
            let mut cur_scheduler = cur_scheduler.borrow_mut();
            if cur_scheduler.is_some() {
                panic!("Attempt to initialize an Scheduler on thread where another Scheduler is running.");
            }

            let handle = Handle::new(Arc::new(Scheduler {
                context_name: context_name.clone(),
                max_throttling,
                tasks: TaskQueue::new(context_name),
                cleanup_ops: ConcurrentQueue::bounded(1000),
                must_awake: Mutex::new(false),
                must_awake_cvar: Condvar::new(),
            }));

            *cur_scheduler = Some(handle.downgrade());

            handle
        });

        Reactor::init(handle.max_throttling());

        handle
    }

    pub fn block_on<F>(future: F) -> F::Output
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        assert!(
            !Scheduler::is_scheduler_thread(),
            "Attempt to block within an existing Scheduler thread."
        );
        let handle = Scheduler::init(Scheduler::DUMMY_NAME.into(), Duration::ZERO);
        let this = Arc::clone(&handle.0.scheduler);

        let (task_id, task) = this.tasks.add(async move {
            let res = future.await;

            let task_id = TaskId::current().unwrap();
            while handle.has_sub_tasks(task_id) {
                if handle.drain_sub_tasks(task_id).await.is_err() {
                    break;
                }
            }

            res
        });

        gst_trace!(RUNTIME_CAT, "Blocking on current thread with {:?}", task_id);

        let _guard = CallOnDrop::new(|| {
            gst_trace!(
                RUNTIME_CAT,
                "Blocking on current thread with {:?} done",
                task_id,
            );
        });

        match this.block_on_priv(task) {
            Ok(res) => res,
            Err(e) => {
                gst_error!(
                    RUNTIME_CAT,
                    "Panic blocking on Context {}",
                    &Scheduler::DUMMY_NAME
                );

                panic::resume_unwind(e);
            }
        }
    }

    fn block_on_priv<F>(&self, future: F) -> std::thread::Result<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        let waker = waker_fn(|| ());
        let cx = &mut std::task::Context::from_waker(&waker);
        pin_mut!(future);

        let _guard = CallOnDrop::new(|| Scheduler::close(Arc::clone(&self.context_name)));

        let mut last;
        loop {
            last = Instant::now();

            if let Poll::Ready(t) = future.as_mut().poll(cx) {
                break Ok(t);
            }

            Reactor::with_mut(|reactor| {
                while let Ok(op) = self.cleanup_ops.pop() {
                    let _ = reactor.remove_io(&op.0);
                }

                reactor.react().ok()
            });

            loop {
                match self.tasks.pop_runnable() {
                    Err(_) => break,
                    Ok(runnable) => {
                        panic::catch_unwind(|| runnable.run()).map_err(|err| {
                            gst_error!(
                                RUNTIME_CAT,
                                "A task has panicked within Context {}",
                                self.context_name
                            );

                            err
                        })?;
                    }
                }
            }

            let mut must_awake = self.must_awake.lock().unwrap();
            let mut must_awake = loop {
                if let Some(wait_duration) = self.max_throttling.checked_sub(last.elapsed()) {
                    let result = self
                        .must_awake_cvar
                        .wait_timeout(must_awake, wait_duration)
                        .unwrap();

                    must_awake = result.0;
                    if *must_awake {
                        break must_awake;
                    }
                } else {
                    break must_awake;
                }
            };

            *must_awake = false;
        }
    }

    fn wake_up(&self) {
        let mut must_awake = self.must_awake.lock().unwrap();
        *must_awake = true;
        self.must_awake_cvar.notify_one();
    }

    fn close(context_name: Arc<str>) {
        gst_trace!(
            RUNTIME_CAT,
            "Closing Scheduler for Context {}",
            context_name,
        );

        Reactor::close();

        let _ = CURRENT_SCHEDULER.try_with(|cur_scheduler| {
            *cur_scheduler.borrow_mut() = None;
        });
    }

    pub fn is_scheduler_thread() -> bool {
        CURRENT_SCHEDULER.with(|cur_scheduler| cur_scheduler.borrow().is_some())
    }

    pub fn current() -> Option<Handle> {
        CURRENT_SCHEDULER.with(|cur_scheduler| {
            cur_scheduler
                .borrow()
                .as_ref()
                .and_then(HandleWeak::upgrade)
        })
    }

    pub fn is_current(&self) -> bool {
        CURRENT_SCHEDULER.with(|cur_scheduler| {
            cur_scheduler
                .borrow()
                .as_ref()
                .and_then(HandleWeak::upgrade)
                .map_or(false, |cur| {
                    std::ptr::eq(self, Arc::as_ptr(&cur.0.scheduler))
                })
        })
    }
}

impl Drop for Scheduler {
    fn drop(&mut self) {
        gst_debug!(
            RUNTIME_CAT,
            "Terminated: Scheduler for Context {}",
            self.context_name
        );
    }
}

#[derive(Debug)]
struct SchedulerShutdown {
    scheduler: Arc<Scheduler>,
    sender: Option<oneshot::Sender<()>>,
    join: Option<thread::JoinHandle<()>>,
}

impl SchedulerShutdown {
    fn new(scheduler: Arc<Scheduler>) -> Self {
        SchedulerShutdown {
            scheduler,
            sender: None,
            join: None,
        }
    }

    fn clear(&mut self) {
        self.sender = None;
        self.join = None;
    }
}

impl Drop for SchedulerShutdown {
    fn drop(&mut self) {
        if let Some(sender) = self.sender.take() {
            gst_debug!(
                RUNTIME_CAT,
                "Shutting down Scheduler thread for Context {}",
                self.scheduler.context_name
            );
            drop(sender);

            // Don't block shutting down itself
            if !self.scheduler.is_current() {
                if let Some(join_handler) = self.join.take() {
                    gst_trace!(
                        RUNTIME_CAT,
                        "Waiting for Scheduler thread to shutdown for Context {}",
                        self.scheduler.context_name
                    );

                    let _ = join_handler.join();
                }
            }
        }
    }
}

#[derive(Debug)]
struct HandleInner {
    scheduler: Arc<Scheduler>,
    shutdown: Mutex<SchedulerShutdown>,
}

#[derive(Clone, Debug)]
pub(super) struct HandleWeak(Weak<HandleInner>);

impl HandleWeak {
    pub(super) fn upgrade(&self) -> Option<Handle> {
        self.0.upgrade().map(Handle)
    }
}

#[derive(Clone, Debug)]
pub(super) struct Handle(Arc<HandleInner>);

impl Handle {
    fn new(scheduler: Arc<Scheduler>) -> Self {
        Handle(Arc::new(HandleInner {
            shutdown: Mutex::new(SchedulerShutdown::new(Arc::clone(&scheduler))),
            scheduler,
        }))
    }

    fn set_shutdown(&self, sender: oneshot::Sender<()>, join: thread::JoinHandle<()>) {
        let mut shutdown = self.0.shutdown.lock().unwrap();
        shutdown.sender = Some(sender);
        shutdown.join = Some(join);
    }

    pub fn context_name(&self) -> &str {
        &self.0.scheduler.context_name
    }

    pub fn max_throttling(&self) -> Duration {
        self.0.scheduler.max_throttling
    }

    /// Executes the provided function relatively to this [`Scheduler`]'s [`Reactor`].
    ///
    /// Usefull to initialze i/o sources and timers from outside
    /// of a [`Scheduler`].
    ///
    /// # Panic
    ///
    /// This will block current thread and would panic if run
    /// from the [`Scheduler`].
    pub fn enter<'a, F, O>(&'a self, f: F) -> O
    where
        F: FnOnce() -> O + Send + 'a,
        O: Send + 'a,
    {
        assert!(!self.0.scheduler.is_current());

        // Safety: bounding `self` to `'a` and blocking on the task
        // ensures that the lifetime bounds satisfy the safety
        // requirements for `TaskQueue::add_sync`.
        let task = unsafe { self.0.scheduler.tasks.add_sync(f) };
        self.0.scheduler.wake_up();
        futures::executor::block_on(task)
    }

    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        let (task_id, task) = self.0.scheduler.tasks.add(future);
        JoinHandle::new(task_id, task, self)
    }

    pub fn spawn_and_awake<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        let (task_id, task) = self.0.scheduler.tasks.add(future);
        self.0.scheduler.wake_up();
        JoinHandle::new(task_id, task, self)
    }

    pub fn remove_soure(&self, source: Arc<Source>) {
        if self
            .0
            .scheduler
            .cleanup_ops
            .push(CleanUpOps(source))
            .is_err()
        {
            gst_warning!(RUNTIME_CAT, "scheduler: cleanup_ops is full");
        }
    }

    pub fn has_sub_tasks(&self, task_id: TaskId) -> bool {
        self.0.scheduler.tasks.has_sub_tasks(task_id)
    }

    pub fn add_sub_task<T>(&self, task_id: TaskId, sub_task: T) -> Result<(), T>
    where
        T: Future<Output = SubTaskOutput> + Send + 'static,
    {
        self.0.scheduler.tasks.add_sub_task(task_id, sub_task)
    }

    pub fn downgrade(&self) -> HandleWeak {
        HandleWeak(self.0.downgrade())
    }

    pub async fn drain_sub_tasks(&self, task_id: TaskId) -> SubTaskOutput {
        let sub_tasks_fut = self.0.scheduler.tasks.drain_sub_tasks(task_id);
        sub_tasks_fut.await
    }
}

impl PartialEq for Handle {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.0, &other.0)
    }
}

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

    #[test]
    fn block_on_task_join_handle() {
        use std::sync::mpsc;

        let (join_sender, join_receiver) = mpsc::channel();
        let (shutdown_sender, shutdown_receiver) = oneshot::channel();

        std::thread::spawn(move || {
            let handle =
                Scheduler::init("block_on_task_join_handle".into(), Duration::from_millis(2));
            let join_handle = handle.spawn(async {
                Timer::after(Duration::from_millis(5)).await;
                42
            });

            let _ = join_sender.send(join_handle);
            let _ = handle.0.scheduler.block_on_priv(shutdown_receiver);
        });

        let task_join_handle = join_receiver.recv().unwrap();
        let res = Scheduler::block_on(task_join_handle).unwrap();

        let _ = shutdown_sender.send(());

        assert_eq!(res, 42);
    }

    #[test]
    fn block_on_timer() {
        let res = Scheduler::block_on(async {
            Timer::after(Duration::from_millis(5)).await;
            42
        });

        assert_eq!(res, 42);
    }

    #[test]
    fn enter_non_static() {
        let handle = Scheduler::start("enter_non_static", Duration::from_millis(2));

        let mut flag = false;
        handle.enter(|| flag = true);
        assert!(flag);
    }
}
<commit_msg>ts/runtime: rewrite runnable loop<commit_after>// Copyright (C) 2018-2020 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2019-2021 François Laignel <fengalin@free.fr>
//
// Take a look at the license at the top of the repository in the LICENSE file.

use concurrent_queue::ConcurrentQueue;

use futures::channel::oneshot;
use futures::pin_mut;

use gio::glib::clone::Downgrade;
use gst::{gst_debug, gst_error, gst_trace, gst_warning};

use std::cell::RefCell;
use std::future::Future;
use std::panic;
use std::sync::mpsc as sync_mpsc;
use std::sync::{Arc, Condvar, Mutex, Weak};
use std::task::Poll;
use std::thread;
use std::time::{Duration, Instant};

use waker_fn::waker_fn;

use super::task::{SubTaskOutput, TaskId, TaskQueue};
use super::{CallOnDrop, JoinHandle, Reactor, Source};
use crate::runtime::RUNTIME_CAT;

thread_local! {
    static CURRENT_SCHEDULER: RefCell<Option<HandleWeak>> = RefCell::new(None);
}

#[derive(Debug)]
struct CleanUpOps(Arc<Source>);

#[derive(Debug)]
pub(super) struct Scheduler {
    context_name: Arc<str>,
    max_throttling: Duration,
    tasks: TaskQueue,
    cleanup_ops: ConcurrentQueue<CleanUpOps>,
    must_awake: Mutex<bool>,
    must_awake_cvar: Condvar,
}

impl Scheduler {
    pub const DUMMY_NAME: &'static str = "DUMMY";

    pub fn start(context_name: &str, max_throttling: Duration) -> Handle {
        // Name the thread so that it appears in panic messages.
        let thread = thread::Builder::new().name(context_name.to_string());

        let (handle_sender, handle_receiver) = sync_mpsc::channel();
        let (shutdown_sender, shutdown_receiver) = oneshot::channel();
        let context_name = Arc::from(context_name);
        let thread_ctx_name = Arc::clone(&context_name);
        let join = thread
            .spawn(move || {
                gst_debug!(
                    RUNTIME_CAT,
                    "Started Scheduler thread for Context {}",
                    thread_ctx_name
                );

                let handle = Scheduler::init(Arc::clone(&thread_ctx_name), max_throttling);
                let this = Arc::clone(&handle.0.scheduler);
                handle_sender.send(handle.clone()).unwrap();

                match this.block_on_priv(shutdown_receiver) {
                    Ok(_) => {
                        gst_debug!(
                            RUNTIME_CAT,
                            "Scheduler thread shut down for Context {}",
                            thread_ctx_name
                        );
                    }
                    Err(e) => {
                        gst_error!(
                            RUNTIME_CAT,
                            "Scheduler thread shut down due to an error within Context {}",
                            thread_ctx_name
                        );

                        // We are shutting down on our own initiative
                        if let Ok(mut shutdown) = handle.0.shutdown.lock() {
                            shutdown.clear();
                        }

                        panic::resume_unwind(e);
                    }
                }
            })
            .expect("Failed to spawn Scheduler thread");

        let handle = handle_receiver.recv().expect("Context thread init failed");
        handle.set_shutdown(shutdown_sender, join);

        handle
    }

    fn init(context_name: Arc<str>, max_throttling: Duration) -> Handle {
        let handle = CURRENT_SCHEDULER.with(|cur_scheduler| {
            let mut cur_scheduler = cur_scheduler.borrow_mut();
            if cur_scheduler.is_some() {
                panic!("Attempt to initialize an Scheduler on thread where another Scheduler is running.");
            }

            let handle = Handle::new(Arc::new(Scheduler {
                context_name: context_name.clone(),
                max_throttling,
                tasks: TaskQueue::new(context_name),
                cleanup_ops: ConcurrentQueue::bounded(1000),
                must_awake: Mutex::new(false),
                must_awake_cvar: Condvar::new(),
            }));

            *cur_scheduler = Some(handle.downgrade());

            handle
        });

        Reactor::init(handle.max_throttling());

        handle
    }

    pub fn block_on<F>(future: F) -> F::Output
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        assert!(
            !Scheduler::is_scheduler_thread(),
            "Attempt to block within an existing Scheduler thread."
        );
        let handle = Scheduler::init(Scheduler::DUMMY_NAME.into(), Duration::ZERO);
        let this = Arc::clone(&handle.0.scheduler);

        let (task_id, task) = this.tasks.add(async move {
            let res = future.await;

            let task_id = TaskId::current().unwrap();
            while handle.has_sub_tasks(task_id) {
                if handle.drain_sub_tasks(task_id).await.is_err() {
                    break;
                }
            }

            res
        });

        gst_trace!(RUNTIME_CAT, "Blocking on current thread with {:?}", task_id);

        let _guard = CallOnDrop::new(|| {
            gst_trace!(
                RUNTIME_CAT,
                "Blocking on current thread with {:?} done",
                task_id,
            );
        });

        match this.block_on_priv(task) {
            Ok(res) => res,
            Err(e) => {
                gst_error!(
                    RUNTIME_CAT,
                    "Panic blocking on Context {}",
                    &Scheduler::DUMMY_NAME
                );

                panic::resume_unwind(e);
            }
        }
    }

    fn block_on_priv<F>(&self, future: F) -> std::thread::Result<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        let waker = waker_fn(|| ());
        let cx = &mut std::task::Context::from_waker(&waker);
        pin_mut!(future);

        let _guard = CallOnDrop::new(|| Scheduler::close(Arc::clone(&self.context_name)));

        let mut last;
        loop {
            last = Instant::now();

            if let Poll::Ready(t) = future.as_mut().poll(cx) {
                break Ok(t);
            }

            Reactor::with_mut(|reactor| {
                while let Ok(op) = self.cleanup_ops.pop() {
                    let _ = reactor.remove_io(&op.0);
                }

                reactor.react().ok()
            });

            while let Ok(runnable) = self.tasks.pop_runnable() {
                panic::catch_unwind(|| runnable.run()).map_err(|err| {
                    gst_error!(
                        RUNTIME_CAT,
                        "A task has panicked within Context {}",
                        self.context_name
                    );

                    err
                })?;
            }

            let mut must_awake = self.must_awake.lock().unwrap();
            let mut must_awake = loop {
                if let Some(wait_duration) = self.max_throttling.checked_sub(last.elapsed()) {
                    let result = self
                        .must_awake_cvar
                        .wait_timeout(must_awake, wait_duration)
                        .unwrap();

                    must_awake = result.0;
                    if *must_awake {
                        break must_awake;
                    }
                } else {
                    break must_awake;
                }
            };

            *must_awake = false;
        }
    }

    fn wake_up(&self) {
        let mut must_awake = self.must_awake.lock().unwrap();
        *must_awake = true;
        self.must_awake_cvar.notify_one();
    }

    fn close(context_name: Arc<str>) {
        gst_trace!(
            RUNTIME_CAT,
            "Closing Scheduler for Context {}",
            context_name,
        );

        Reactor::close();

        let _ = CURRENT_SCHEDULER.try_with(|cur_scheduler| {
            *cur_scheduler.borrow_mut() = None;
        });
    }

    pub fn is_scheduler_thread() -> bool {
        CURRENT_SCHEDULER.with(|cur_scheduler| cur_scheduler.borrow().is_some())
    }

    pub fn current() -> Option<Handle> {
        CURRENT_SCHEDULER.with(|cur_scheduler| {
            cur_scheduler
                .borrow()
                .as_ref()
                .and_then(HandleWeak::upgrade)
        })
    }

    pub fn is_current(&self) -> bool {
        CURRENT_SCHEDULER.with(|cur_scheduler| {
            cur_scheduler
                .borrow()
                .as_ref()
                .and_then(HandleWeak::upgrade)
                .map_or(false, |cur| {
                    std::ptr::eq(self, Arc::as_ptr(&cur.0.scheduler))
                })
        })
    }
}

impl Drop for Scheduler {
    fn drop(&mut self) {
        gst_debug!(
            RUNTIME_CAT,
            "Terminated: Scheduler for Context {}",
            self.context_name
        );
    }
}

#[derive(Debug)]
struct SchedulerShutdown {
    scheduler: Arc<Scheduler>,
    sender: Option<oneshot::Sender<()>>,
    join: Option<thread::JoinHandle<()>>,
}

impl SchedulerShutdown {
    fn new(scheduler: Arc<Scheduler>) -> Self {
        SchedulerShutdown {
            scheduler,
            sender: None,
            join: None,
        }
    }

    fn clear(&mut self) {
        self.sender = None;
        self.join = None;
    }
}

impl Drop for SchedulerShutdown {
    fn drop(&mut self) {
        if let Some(sender) = self.sender.take() {
            gst_debug!(
                RUNTIME_CAT,
                "Shutting down Scheduler thread for Context {}",
                self.scheduler.context_name
            );
            drop(sender);

            // Don't block shutting down itself
            if !self.scheduler.is_current() {
                if let Some(join_handler) = self.join.take() {
                    gst_trace!(
                        RUNTIME_CAT,
                        "Waiting for Scheduler thread to shutdown for Context {}",
                        self.scheduler.context_name
                    );

                    let _ = join_handler.join();
                }
            }
        }
    }
}

#[derive(Debug)]
struct HandleInner {
    scheduler: Arc<Scheduler>,
    shutdown: Mutex<SchedulerShutdown>,
}

#[derive(Clone, Debug)]
pub(super) struct HandleWeak(Weak<HandleInner>);

impl HandleWeak {
    pub(super) fn upgrade(&self) -> Option<Handle> {
        self.0.upgrade().map(Handle)
    }
}

#[derive(Clone, Debug)]
pub(super) struct Handle(Arc<HandleInner>);

impl Handle {
    fn new(scheduler: Arc<Scheduler>) -> Self {
        Handle(Arc::new(HandleInner {
            shutdown: Mutex::new(SchedulerShutdown::new(Arc::clone(&scheduler))),
            scheduler,
        }))
    }

    fn set_shutdown(&self, sender: oneshot::Sender<()>, join: thread::JoinHandle<()>) {
        let mut shutdown = self.0.shutdown.lock().unwrap();
        shutdown.sender = Some(sender);
        shutdown.join = Some(join);
    }

    pub fn context_name(&self) -> &str {
        &self.0.scheduler.context_name
    }

    pub fn max_throttling(&self) -> Duration {
        self.0.scheduler.max_throttling
    }

    /// Executes the provided function relatively to this [`Scheduler`]'s [`Reactor`].
    ///
    /// Usefull to initialze i/o sources and timers from outside
    /// of a [`Scheduler`].
    ///
    /// # Panic
    ///
    /// This will block current thread and would panic if run
    /// from the [`Scheduler`].
    pub fn enter<'a, F, O>(&'a self, f: F) -> O
    where
        F: FnOnce() -> O + Send + 'a,
        O: Send + 'a,
    {
        assert!(!self.0.scheduler.is_current());

        // Safety: bounding `self` to `'a` and blocking on the task
        // ensures that the lifetime bounds satisfy the safety
        // requirements for `TaskQueue::add_sync`.
        let task = unsafe { self.0.scheduler.tasks.add_sync(f) };
        self.0.scheduler.wake_up();
        futures::executor::block_on(task)
    }

    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        let (task_id, task) = self.0.scheduler.tasks.add(future);
        JoinHandle::new(task_id, task, self)
    }

    pub fn spawn_and_awake<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        let (task_id, task) = self.0.scheduler.tasks.add(future);
        self.0.scheduler.wake_up();
        JoinHandle::new(task_id, task, self)
    }

    pub fn remove_soure(&self, source: Arc<Source>) {
        if self
            .0
            .scheduler
            .cleanup_ops
            .push(CleanUpOps(source))
            .is_err()
        {
            gst_warning!(RUNTIME_CAT, "scheduler: cleanup_ops is full");
        }
    }

    pub fn has_sub_tasks(&self, task_id: TaskId) -> bool {
        self.0.scheduler.tasks.has_sub_tasks(task_id)
    }

    pub fn add_sub_task<T>(&self, task_id: TaskId, sub_task: T) -> Result<(), T>
    where
        T: Future<Output = SubTaskOutput> + Send + 'static,
    {
        self.0.scheduler.tasks.add_sub_task(task_id, sub_task)
    }

    pub fn downgrade(&self) -> HandleWeak {
        HandleWeak(self.0.downgrade())
    }

    pub async fn drain_sub_tasks(&self, task_id: TaskId) -> SubTaskOutput {
        let sub_tasks_fut = self.0.scheduler.tasks.drain_sub_tasks(task_id);
        sub_tasks_fut.await
    }
}

impl PartialEq for Handle {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.0, &other.0)
    }
}

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

    #[test]
    fn block_on_task_join_handle() {
        use std::sync::mpsc;

        let (join_sender, join_receiver) = mpsc::channel();
        let (shutdown_sender, shutdown_receiver) = oneshot::channel();

        std::thread::spawn(move || {
            let handle =
                Scheduler::init("block_on_task_join_handle".into(), Duration::from_millis(2));
            let join_handle = handle.spawn(async {
                Timer::after(Duration::from_millis(5)).await;
                42
            });

            let _ = join_sender.send(join_handle);
            let _ = handle.0.scheduler.block_on_priv(shutdown_receiver);
        });

        let task_join_handle = join_receiver.recv().unwrap();
        let res = Scheduler::block_on(task_join_handle).unwrap();

        let _ = shutdown_sender.send(());

        assert_eq!(res, 42);
    }

    #[test]
    fn block_on_timer() {
        let res = Scheduler::block_on(async {
            Timer::after(Duration::from_millis(5)).await;
            42
        });

        assert_eq!(res, 42);
    }

    #[test]
    fn enter_non_static() {
        let handle = Scheduler::start("enter_non_static", Duration::from_millis(2));

        let mut flag = false;
        handle.enter(|| flag = true);
        assert!(flag);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

#[cfg(test)]
macro_rules! assert_state {
    ($machine:ident, $state:ident) => {
        assert!(
            if let State::$state(_) = $machine { true } else { false },
            "Failed to get to {} state.",
            stringify!($state),
        );
    };
}
<commit_msg>updatehub: tests: Use 'matches!' macro to simplify code<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

#[cfg(test)]
macro_rules! assert_state {
    ($machine:ident, $state:ident) => {
        assert!(
            matches!($machine, State::$state(_)),
            "Failed to get to {} state.",
            stringify!($state),
        );
    };
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

#[macro_export]
macro_rules! router (
    ($($method:ident $path:expr => |$req:ident, $res:ident| $b:block)+) => (
        {
            use nickel::{HttpRouter, MiddlewareResult};
            use nickel::router::ResponseFinalizer;
            let mut router = nickel::Router::new();
            #[inline(always)]
            fn restrict<R: ResponseFinalizer>(r: R, res: &mut nickel::Response) -> MiddlewareResult {
                r.respond(res)
            }

            $(
                {
                    #[allow(unused_variable)]
                    fn f($req: &nickel::Request, $res: &mut nickel::Response) -> MiddlewareResult {
                        restrict($b, $res)
                    }
                    router.$method($path, f)
                }
            );*

            router
        }
    )
)
<commit_msg>fix(macros): remove warnings from lint name change<commit_after>#![feature(macro_rules)]

#[macro_export]
macro_rules! router (
    ($($method:ident $path:expr => |$req:ident, $res:ident| $b:block)+) => (
        {
            use nickel::{HttpRouter, MiddlewareResult};
            use nickel::router::ResponseFinalizer;
            let mut router = nickel::Router::new();
            #[inline(always)]
            fn restrict<R: ResponseFinalizer>(r: R, res: &mut nickel::Response) -> MiddlewareResult {
                r.respond(res)
            }

            $(
                {
                    #[allow(unused_variables)]
                    fn f($req: &nickel::Request, $res: &mut nickel::Response) -> MiddlewareResult {
                        restrict($b, $res)
                    }
                    router.$method($path, f)
                }
            );*

            router
        }
    )
)
<|endoftext|>


<commit_before>pub use lucet_wiggle_generate::bindings;
pub use lucet_wiggle_macro::from_witx;
pub use wiggle::{
    witx, BorrowChecker, GuestError, GuestErrorType, GuestMemory, GuestPtr, GuestType,
    GuestTypeTransparent, Pointee,
};

pub mod generate {
    pub use lucet_wiggle_generate::*;
}

pub mod runtime {
    use lucet_runtime::vmctx::Vmctx;
    use wiggle::{BorrowChecker, GuestMemory};

    pub struct LucetMemory<'a> {
        vmctx: &'a Vmctx,
        bc: BorrowChecker,
    }

    impl<'a> LucetMemory<'a> {
        pub fn new(vmctx: &'a Vmctx) -> LucetMemory {
            LucetMemory {
                vmctx,
                // Safety: we only construct a LucetMemory at the entry point of hostcalls, and
                // hostcalls are not re-entered, therefore there is exactly one BorrowChecker per
                // memory.
                bc: unsafe { BorrowChecker::new() },
            }
        }
    }

    unsafe impl<'a> GuestMemory for LucetMemory<'a> {
        fn base(&self) -> (*mut u8, u32) {
            let mem = self.vmctx.heap_mut();
            let len = mem.len() as u32;
            let ptr = mem.as_ptr();
            (ptr as *mut u8, len)
        }
        fn borrow_checker(&self) -> &BorrowChecker {
            &self.bc
        }
    }
}
<commit_msg>lucet-wiggle: re-export GuestStr and GuestSlice<commit_after>pub use lucet_wiggle_generate::bindings;
pub use lucet_wiggle_macro::from_witx;
pub use wiggle::{
    witx, BorrowChecker, GuestError, GuestErrorType, GuestMemory, GuestPtr, GuestSlice, GuestStr,
    GuestType, GuestTypeTransparent, Pointee,
};

pub mod generate {
    pub use lucet_wiggle_generate::*;
}

pub mod runtime {
    use lucet_runtime::vmctx::Vmctx;
    use wiggle::{BorrowChecker, GuestMemory};

    pub struct LucetMemory<'a> {
        vmctx: &'a Vmctx,
        bc: BorrowChecker,
    }

    impl<'a> LucetMemory<'a> {
        pub fn new(vmctx: &'a Vmctx) -> LucetMemory {
            LucetMemory {
                vmctx,
                // Safety: we only construct a LucetMemory at the entry point of hostcalls, and
                // hostcalls are not re-entered, therefore there is exactly one BorrowChecker per
                // memory.
                bc: unsafe { BorrowChecker::new() },
            }
        }
    }

    unsafe impl<'a> GuestMemory for LucetMemory<'a> {
        fn base(&self) -> (*mut u8, u32) {
            let mem = self.vmctx.heap_mut();
            let len = mem.len() as u32;
            let ptr = mem.as_ptr();
            (ptr as *mut u8, len)
        }
        fn borrow_checker(&self) -> &BorrowChecker {
            &self.bc
        }
    }
}
<|endoftext|>


<commit_before>pub fn remove_duplicates(s: String, k: i32) -> String {
    let mut stack: Vec<char> = vec![];
    let k = k as usize;
    let (mut last_count, mut last_count_vec, mut last) = (0, vec![], ' ');

    for c in s.chars() {
        println!(
            "last_count: {}, last_count_vec: {:?}, last: {}",
            last_count, last_count_vec, last
        );

        if c == last {
            last_count += 1;
            if last_count == k {
                stack.truncate(stack.len() - k + 1);
                last_count_vec.pop();
            }
        } else {
            last_count_vec.push(last_count + 1);
            last = c;
            last_count = 0;
        }
    }

    String::from_iter(stack)
}

fn main() {
    dbg!(remove_duplicates("deeedbbcccbdaa".into(), 3));
}
<commit_msg>finish<commit_after>pub fn remove_duplicates(s: String, k: i32) -> String {
    let mut stack: Vec<char> = vec![];
    let k = k as usize;
    let mut cc = s.chars();
    let first = cc.next().unwrap();
    let (mut last_count, mut last_count_vec, mut last) = (1, vec![], first);
    stack.push(first);

    for c in cc {
        // println!(
        //     "last_count: {}, last_count_vec: {:?}, last: {}, stack: {:?}",
        //     last_count, last_count_vec, last, stack
        // );
        if c == last {
            last_count += 1;
            stack.push(c);

            if last_count == k {
                stack.truncate(stack.len() - k);
                //println!("stack here? {:?}", stack);
                last_count = last_count_vec.pop().unwrap_or(0);
                last = *stack.last().unwrap_or(&' ');
            }
        } else {
            last_count_vec.push(last_count);
            last = c;
            last_count = 1;
            stack.push(c);
        }
    }

    String::from_iter(stack)
}

fn main() {
    dbg!(remove_duplicates("deeedbbcccbdaa".into(), 3));
    dbg!(remove_duplicates("pbbcggttciiippooaais".into(), 2));
    dbg!(remove_duplicates("abcd".into(), 2));
}
<|endoftext|>


<commit_before>use super::schema::*;
use diesel::*;
use schema_dsl::*;

#[test]
fn selecting_basic_data() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let expected_data = vec![
        ("Sean".to_string(), None::<String>),
        ("Tess".to_string(), None::<String>),
     ];
    let actual_data: Vec<_> = users
        .select((name, hair_color))
        .load(&connection)
        .unwrap();
    assert_eq!(expected_data, actual_data);
}

#[test]
fn selecting_a_struct() {
    use schema::users::dsl::*;
    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let expected_users = vec![
        NewUser::new("Sean", None),
        NewUser::new("Tess", None),
    ];
    let actual_users: Vec<_> = users
        .select((name, hair_color))
        .load(&connection).unwrap();
    assert_eq!(expected_users, actual_users);
}

#[test]
fn with_safe_select() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let select_name = users.select(name);
    let names: Vec<String> = select_name.load(&connection).unwrap();

    assert_eq!(vec!["Sean".to_string(), "Tess".to_string()], names);
}

#[test]
fn with_select_sql() {
    use diesel::expression::dsl::sql;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let select_count = users::table.select(sql::<types::BigInt>("COUNT(*)"));
    let get_count = || select_count.clone().first::<i64>(&connection);

    assert_eq!(Ok(2), get_count());

    connection.execute("INSERT INTO users (name) VALUES ('Jim')")
        .unwrap();

    assert_eq!(Ok(3), get_count());
}

#[test]
fn selecting_nullable_followed_by_non_null() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean')")
        .unwrap();

    let source = users.select((hair_color, name));
    let expected_data = vec![(None::<String>, "Sean".to_string())];
    let data: Vec<_> = source.load(&connection).unwrap();

    assert_eq!(expected_data, data);
}

#[test]
fn selecting_expression_with_bind_param() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let source = users.select(name.eq("Sean".to_string()));
    let expected_data = vec![true, false];
    let actual_data: Vec<_> = source.load(&connection).unwrap();

    assert_eq!(expected_data, actual_data);
}

table! {
    select {
        id -> Integer,
        join -> Integer,
    }
}

#[test]
#[cfg(not(feature="mysql"))] // FIXME: Figure out how to handle tests that modify schema
fn selecting_columns_and_tables_with_reserved_names() {
    use self::select::dsl::*;

    let connection = connection();
    create_table("select", (
        integer("id").primary_key().auto_increment(),
        integer("join").not_null(),
    )).execute(&connection).unwrap();
    connection.execute("INSERT INTO \"select\" (\"join\") VALUES (1), (2), (3)")
        .unwrap();

    let expected_data = vec![(1, 1), (2, 2), (3, 3)];
    let actual_data: Vec<(i32, i32)> = select.load(&connection).unwrap();
    assert_eq!(expected_data, actual_data);

    let expected_data = vec![1, 2, 3];
    let actual_data: Vec<i32> = select.select(join).load(&connection).unwrap();
    assert_eq!(expected_data, actual_data);
}

#[test]
#[cfg(not(feature="mysql"))] // FIXME: Figure out how to handle tests that modify schema
fn selecting_columns_with_different_definition_order() {
    let connection = connection();
    drop_table_cascade(&connection, "users");
    create_table("users", (
        integer("id").primary_key().auto_increment(),
        string("hair_color"),
        string("name").not_null(),
    )).execute(&connection).unwrap();
    let expected_user = User::with_hair_color(1, "Sean", "black");
    insert(&NewUser::new("Sean", Some("black"))).into(users::table)
        .execute(&connection).unwrap();
    let user_from_select = users::table.first(&connection);

    assert_eq!(Ok(&expected_user), user_from_select.as_ref());
}

#[test]
fn selection_using_subselect() {
    use schema::posts::dsl::*;

    let connection = connection_with_sean_and_tess_in_users_table();
    let ids: Vec<i32> = users::table.select(users::id).load(&connection).unwrap();
    let query = format!(
        "INSERT INTO posts (user_id, title) VALUES ({}, 'Hello'), ({}, 'World')",
        ids[0], ids[1]);
    connection.execute(&query).unwrap();

    let users = users::table.filter(users::name.eq("Sean")).select(users::id);
    let data: Vec<String> = posts
        .select(title)
        .filter(user_id.eq_any(users))
        .load(&connection).unwrap();

    assert_eq!(vec!["Hello".to_string()], data);
}
<commit_msg>Fix failing build<commit_after>use super::schema::*;
use diesel::*;
use schema_dsl::*;

#[test]
fn selecting_basic_data() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let expected_data = vec![
        ("Sean".to_string(), None::<String>),
        ("Tess".to_string(), None::<String>),
     ];
    let actual_data: Vec<_> = users
        .select((name, hair_color))
        .load(&connection)
        .unwrap();
    assert_eq!(expected_data, actual_data);
}

#[test]
fn selecting_a_struct() {
    use schema::users::dsl::*;
    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let expected_users = vec![
        NewUser::new("Sean", None),
        NewUser::new("Tess", None),
    ];
    let actual_users: Vec<_> = users
        .select((name, hair_color))
        .load(&connection).unwrap();
    assert_eq!(expected_users, actual_users);
}

#[test]
fn with_safe_select() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let select_name = users.select(name);
    let names: Vec<String> = select_name.load(&connection).unwrap();

    assert_eq!(vec!["Sean".to_string(), "Tess".to_string()], names);
}

#[test]
fn with_select_sql() {
    use diesel::expression::dsl::sql;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let select_count = users::table.select(sql::<types::BigInt>("COUNT(*)"));
    let get_count = || select_count.clone().first::<i64>(&connection);

    assert_eq!(Ok(2), get_count());

    connection.execute("INSERT INTO users (name) VALUES ('Jim')")
        .unwrap();

    assert_eq!(Ok(3), get_count());
}

#[test]
fn selecting_nullable_followed_by_non_null() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean')")
        .unwrap();

    let source = users.select((hair_color, name));
    let expected_data = vec![(None::<String>, "Sean".to_string())];
    let data: Vec<_> = source.load(&connection).unwrap();

    assert_eq!(expected_data, data);
}

#[test]
fn selecting_expression_with_bind_param() {
    use schema::users::dsl::*;

    let connection = connection();
    connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
        .unwrap();

    let source = users.select(name.eq("Sean".to_string()));
    let expected_data = vec![true, false];
    let actual_data = source.load::<bool>(&connection).unwrap();

    assert_eq!(expected_data, actual_data);
}

table! {
    select {
        id -> Integer,
        join -> Integer,
    }
}

#[test]
#[cfg(not(feature="mysql"))] // FIXME: Figure out how to handle tests that modify schema
fn selecting_columns_and_tables_with_reserved_names() {
    use self::select::dsl::*;

    let connection = connection();
    create_table("select", (
        integer("id").primary_key().auto_increment(),
        integer("join").not_null(),
    )).execute(&connection).unwrap();
    connection.execute("INSERT INTO \"select\" (\"join\") VALUES (1), (2), (3)")
        .unwrap();

    let expected_data = vec![(1, 1), (2, 2), (3, 3)];
    let actual_data: Vec<(i32, i32)> = select.load(&connection).unwrap();
    assert_eq!(expected_data, actual_data);

    let expected_data = vec![1, 2, 3];
    let actual_data: Vec<i32> = select.select(join).load(&connection).unwrap();
    assert_eq!(expected_data, actual_data);
}

#[test]
#[cfg(not(feature="mysql"))] // FIXME: Figure out how to handle tests that modify schema
fn selecting_columns_with_different_definition_order() {
    let connection = connection();
    drop_table_cascade(&connection, "users");
    create_table("users", (
        integer("id").primary_key().auto_increment(),
        string("hair_color"),
        string("name").not_null(),
    )).execute(&connection).unwrap();
    let expected_user = User::with_hair_color(1, "Sean", "black");
    insert(&NewUser::new("Sean", Some("black"))).into(users::table)
        .execute(&connection).unwrap();
    let user_from_select = users::table.first(&connection);

    assert_eq!(Ok(&expected_user), user_from_select.as_ref());
}

#[test]
fn selection_using_subselect() {
    use schema::posts::dsl::*;

    let connection = connection_with_sean_and_tess_in_users_table();
    let ids: Vec<i32> = users::table.select(users::id).load(&connection).unwrap();
    let query = format!(
        "INSERT INTO posts (user_id, title) VALUES ({}, 'Hello'), ({}, 'World')",
        ids[0], ids[1]);
    connection.execute(&query).unwrap();

    let users = users::table.filter(users::name.eq("Sean")).select(users::id);
    let data: Vec<String> = posts
        .select(title)
        .filter(user_id.eq_any(users))
        .load(&connection).unwrap();

    assert_eq!(vec!["Hello".to_string()], data);
}
<|endoftext|>