ide_assists/handlers/
destructure_struct_binding.rs

1use hir::HasVisibility;
2use ide_db::{
3    FxHashMap, FxHashSet,
4    assists::AssistId,
5    defs::Definition,
6    helpers::mod_path_to_ast,
7    search::{FileReference, SearchScope},
8};
9use itertools::Itertools;
10use syntax::ast::{HasName, syntax_factory::SyntaxFactory};
11use syntax::syntax_editor::SyntaxEditor;
12use syntax::{AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr, ast};
13
14use crate::{
15    assist_context::{AssistContext, Assists, SourceChangeBuilder},
16    utils::ref_field_expr::determine_ref_and_parens,
17};
18
19// Assist: destructure_struct_binding
20//
21// Destructures a struct binding in place.
22//
23// ```
24// struct Foo {
25//     bar: i32,
26//     baz: i32,
27// }
28// fn main() {
29//     let $0foo = Foo { bar: 1, baz: 2 };
30//     let bar2 = foo.bar;
31//     let baz2 = &foo.baz;
32// }
33// ```
34// ->
35// ```
36// struct Foo {
37//     bar: i32,
38//     baz: i32,
39// }
40// fn main() {
41//     let Foo { bar, baz } = Foo { bar: 1, baz: 2 };
42//     let bar2 = bar;
43//     let baz2 = &baz;
44// }
45// ```
46pub(crate) fn destructure_struct_binding(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
47    let ident_pat = ctx.find_node_at_offset::<ast::IdentPat>()?;
48    let data = collect_data(ident_pat, ctx)?;
49
50    acc.add(
51        AssistId::refactor_rewrite("destructure_struct_binding"),
52        "Destructure struct binding",
53        data.ident_pat.syntax().text_range(),
54        |edit| destructure_struct_binding_impl(ctx, edit, &data),
55    );
56
57    Some(())
58}
59
60fn destructure_struct_binding_impl(
61    ctx: &AssistContext<'_>,
62    builder: &mut SourceChangeBuilder,
63    data: &StructEditData,
64) {
65    let field_names = generate_field_names(ctx, data);
66    let mut editor = builder.make_editor(data.ident_pat.syntax());
67    destructure_pat(ctx, &mut editor, data, &field_names);
68    update_usages(ctx, &mut editor, data, &field_names.into_iter().collect());
69    builder.add_file_edits(ctx.vfs_file_id(), editor);
70}
71
72struct StructEditData {
73    ident_pat: ast::IdentPat,
74    name: ast::Name,
75    kind: hir::StructKind,
76    struct_def_path: hir::ModPath,
77    visible_fields: Vec<hir::Field>,
78    usages: Vec<FileReference>,
79    names_in_scope: FxHashSet<SmolStr>,
80    has_private_members: bool,
81    need_record_field_name: bool,
82    is_ref: bool,
83    edition: Edition,
84}
85
86fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<StructEditData> {
87    let ty = ctx.sema.type_of_binding_in_pat(&ident_pat)?;
88    let hir::Adt::Struct(struct_type) = ty.strip_references().as_adt()? else { return None };
89
90    let module = ctx.sema.scope(ident_pat.syntax())?.module();
91    let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db())));
92    let struct_def = hir::ModuleDef::from(struct_type);
93    let kind = struct_type.kind(ctx.db());
94    let struct_def_path = module.find_path(ctx.db(), struct_def, cfg)?;
95
96    let is_non_exhaustive = struct_def.attrs(ctx.db())?.is_non_exhaustive();
97    let is_foreign_crate =
98        struct_def.module(ctx.db()).is_some_and(|m| m.krate(ctx.db()) != module.krate(ctx.db()));
99
100    let fields = struct_type.fields(ctx.db());
101    let n_fields = fields.len();
102
103    let visible_fields =
104        fields.into_iter().filter(|field| field.is_visible_from(ctx.db(), module)).collect_vec();
105
106    if visible_fields.is_empty() {
107        return None;
108    }
109
110    let has_private_members =
111        (is_non_exhaustive && is_foreign_crate) || visible_fields.len() < n_fields;
112
113    // If private members are present, we can only destructure records
114    if !matches!(kind, hir::StructKind::Record) && has_private_members {
115        return None;
116    }
117
118    let is_ref = ty.is_reference();
119    let need_record_field_name = ident_pat
120        .syntax()
121        .parent()
122        .and_then(ast::RecordPatField::cast)
123        .is_some_and(|field| field.colon_token().is_none());
124
125    let usages = ctx
126        .sema
127        .to_def(&ident_pat)
128        .and_then(|def| {
129            Definition::Local(def)
130                .usages(&ctx.sema)
131                .in_scope(&SearchScope::single_file(ctx.file_id()))
132                .all()
133                .iter()
134                .next()
135                .map(|(_, refs)| refs.to_vec())
136        })
137        .unwrap_or_default();
138
139    let names_in_scope = get_names_in_scope(ctx, &ident_pat, &usages).unwrap_or_default();
140
141    Some(StructEditData {
142        name: ident_pat.name()?,
143        ident_pat,
144        kind,
145        struct_def_path,
146        usages,
147        has_private_members,
148        visible_fields,
149        names_in_scope,
150        need_record_field_name,
151        is_ref,
152        edition: module.krate(ctx.db()).edition(ctx.db()),
153    })
154}
155
156fn get_names_in_scope(
157    ctx: &AssistContext<'_>,
158    ident_pat: &ast::IdentPat,
159    usages: &[FileReference],
160) -> Option<FxHashSet<SmolStr>> {
161    fn last_usage(usages: &[FileReference]) -> Option<SyntaxNode> {
162        usages.last()?.name.syntax().into_node()
163    }
164
165    // If available, find names visible to the last usage of the binding
166    // else, find names visible to the binding itself
167    let last_usage = last_usage(usages);
168    let node = last_usage.as_ref().unwrap_or(ident_pat.syntax());
169    let scope = ctx.sema.scope(node)?;
170
171    let mut names = FxHashSet::default();
172    scope.process_all_names(&mut |name, scope| {
173        if let hir::ScopeDef::Local(_) = scope {
174            names.insert(name.as_str().into());
175        }
176    });
177    Some(names)
178}
179
180fn destructure_pat(
181    _ctx: &AssistContext<'_>,
182    editor: &mut SyntaxEditor,
183    data: &StructEditData,
184    field_names: &[(SmolStr, SmolStr)],
185) {
186    let ident_pat = &data.ident_pat;
187    let name = &data.name;
188
189    let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition);
190    let is_ref = ident_pat.ref_token().is_some();
191    let is_mut = ident_pat.mut_token().is_some();
192
193    let make = SyntaxFactory::with_mappings();
194    let new_pat = match data.kind {
195        hir::StructKind::Tuple => {
196            let ident_pats = field_names.iter().map(|(_, new_name)| {
197                let name = make.name(new_name);
198                ast::Pat::from(make.ident_pat(is_ref, is_mut, name))
199            });
200            ast::Pat::TupleStructPat(make.tuple_struct_pat(struct_path, ident_pats))
201        }
202        hir::StructKind::Record => {
203            let fields = field_names.iter().map(|(old_name, new_name)| {
204                // Use shorthand syntax if possible
205                if old_name == new_name {
206                    make.record_pat_field_shorthand(
207                        make.ident_pat(is_ref, is_mut, make.name(old_name)).into(),
208                    )
209                } else {
210                    make.record_pat_field(
211                        make.name_ref(old_name),
212                        ast::Pat::IdentPat(make.ident_pat(is_ref, is_mut, make.name(new_name))),
213                    )
214                }
215            });
216            let field_list = make
217                .record_pat_field_list(fields, data.has_private_members.then_some(make.rest_pat()));
218
219            ast::Pat::RecordPat(make.record_pat_with_fields(struct_path, field_list))
220        }
221        hir::StructKind::Unit => make.path_pat(struct_path),
222    };
223
224    // If the binding is nested inside a record, we need to wrap the new
225    // destructured pattern in a non-shorthand record field
226    let destructured_pat = if data.need_record_field_name {
227        make.record_pat_field(make.name_ref(&name.to_string()), new_pat).syntax().clone()
228    } else {
229        new_pat.syntax().clone()
230    };
231
232    editor.add_mappings(make.finish_with_mappings());
233    editor.replace(data.ident_pat.syntax(), destructured_pat);
234}
235
236fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<(SmolStr, SmolStr)> {
237    match data.kind {
238        hir::StructKind::Tuple => data
239            .visible_fields
240            .iter()
241            .enumerate()
242            .map(|(index, _)| {
243                let new_name = new_field_name((format!("_{index}")).into(), &data.names_in_scope);
244                (index.to_string().into(), new_name)
245            })
246            .collect(),
247        hir::StructKind::Record => data
248            .visible_fields
249            .iter()
250            .map(|field| {
251                let field_name = field.name(ctx.db()).display_no_db(data.edition).to_smolstr();
252                let new_name = new_field_name(field_name.clone(), &data.names_in_scope);
253                (field_name, new_name)
254            })
255            .collect(),
256        hir::StructKind::Unit => Vec::new(),
257    }
258}
259
260fn new_field_name(base_name: SmolStr, names_in_scope: &FxHashSet<SmolStr>) -> SmolStr {
261    let mut name = base_name.clone();
262    let mut i = 1;
263    while names_in_scope.contains(&name) {
264        name = format!("{base_name}_{i}").into();
265        i += 1;
266    }
267    name
268}
269
270fn update_usages(
271    ctx: &AssistContext<'_>,
272    editor: &mut SyntaxEditor,
273    data: &StructEditData,
274    field_names: &FxHashMap<SmolStr, SmolStr>,
275) {
276    let make = SyntaxFactory::with_mappings();
277    let edits = data
278        .usages
279        .iter()
280        .filter_map(|r| build_usage_edit(ctx, &make, data, r, field_names))
281        .collect_vec();
282    editor.add_mappings(make.finish_with_mappings());
283    for (old, new) in edits {
284        editor.replace(old, new);
285    }
286}
287
288fn build_usage_edit(
289    ctx: &AssistContext<'_>,
290    make: &SyntaxFactory,
291    data: &StructEditData,
292    usage: &FileReference,
293    field_names: &FxHashMap<SmolStr, SmolStr>,
294) -> Option<(SyntaxNode, SyntaxNode)> {
295    match usage.name.syntax().ancestors().find_map(ast::FieldExpr::cast) {
296        Some(field_expr) => Some({
297            let field_name: SmolStr = field_expr.name_ref()?.to_string().into();
298            let new_field_name = field_names.get(&field_name)?;
299            let new_expr = ast::make::expr_path(ast::make::ext::ident_path(new_field_name));
300
301            // If struct binding is a reference, we might need to deref field usages
302            if data.is_ref {
303                let (replace_expr, ref_data) = determine_ref_and_parens(ctx, &field_expr);
304                (
305                    replace_expr.syntax().clone_for_update(),
306                    ref_data.wrap_expr(new_expr).syntax().clone_for_update(),
307                )
308            } else {
309                (field_expr.syntax().clone(), new_expr.syntax().clone_for_update())
310            }
311        }),
312        None => Some((
313            usage.name.syntax().as_node().unwrap().clone(),
314            make.expr_macro(
315                ast::make::ext::ident_path("todo"),
316                make.token_tree(syntax::SyntaxKind::L_PAREN, []),
317            )
318            .syntax()
319            .clone(),
320        )),
321    }
322}
323
324#[cfg(test)]
325mod tests {
326    use super::*;
327
328    use crate::tests::{check_assist, check_assist_not_applicable};
329
330    #[test]
331    fn record_struct() {
332        check_assist(
333            destructure_struct_binding,
334            r#"
335            struct Foo { bar: i32, baz: i32 }
336
337            fn main() {
338                let $0foo = Foo { bar: 1, baz: 2 };
339                let bar2 = foo.bar;
340                let baz2 = &foo.baz;
341
342                let foo2 = foo;
343            }
344            "#,
345            r#"
346            struct Foo { bar: i32, baz: i32 }
347
348            fn main() {
349                let Foo { bar, baz } = Foo { bar: 1, baz: 2 };
350                let bar2 = bar;
351                let baz2 = &baz;
352
353                let foo2 = todo!();
354            }
355            "#,
356        )
357    }
358
359    #[test]
360    fn tuple_struct() {
361        check_assist(
362            destructure_struct_binding,
363            r#"
364            struct Foo(i32, i32);
365
366            fn main() {
367                let $0foo = Foo(1, 2);
368                let bar2 = foo.0;
369                let baz2 = foo.1;
370
371                let foo2 = foo;
372            }
373            "#,
374            r#"
375            struct Foo(i32, i32);
376
377            fn main() {
378                let Foo(_0, _1) = Foo(1, 2);
379                let bar2 = _0;
380                let baz2 = _1;
381
382                let foo2 = todo!();
383            }
384            "#,
385        )
386    }
387
388    #[test]
389    fn unit_struct() {
390        check_assist_not_applicable(
391            destructure_struct_binding,
392            r#"
393            struct Foo;
394
395            fn main() {
396                let $0foo = Foo;
397            }
398            "#,
399        )
400    }
401
402    #[test]
403    fn in_foreign_crate() {
404        check_assist(
405            destructure_struct_binding,
406            r#"
407            //- /lib.rs crate:dep
408            pub struct Foo { pub bar: i32 };
409
410            //- /main.rs crate:main deps:dep
411            fn main() {
412                let $0foo = dep::Foo { bar: 1 };
413                let bar2 = foo.bar;
414            }
415            "#,
416            r#"
417            fn main() {
418                let dep::Foo { bar } = dep::Foo { bar: 1 };
419                let bar2 = bar;
420            }
421            "#,
422        )
423    }
424
425    #[test]
426    fn non_exhaustive_record_appends_rest() {
427        check_assist(
428            destructure_struct_binding,
429            r#"
430            //- /lib.rs crate:dep
431            #[non_exhaustive]
432            pub struct Foo { pub bar: i32 };
433
434            //- /main.rs crate:main deps:dep
435            fn main($0foo: dep::Foo) {
436                let bar2 = foo.bar;
437            }
438            "#,
439            r#"
440            fn main(dep::Foo { bar, .. }: dep::Foo) {
441                let bar2 = bar;
442            }
443            "#,
444        )
445    }
446
447    #[test]
448    fn non_exhaustive_tuple_not_applicable() {
449        check_assist_not_applicable(
450            destructure_struct_binding,
451            r#"
452            //- /lib.rs crate:dep
453            #[non_exhaustive]
454            pub struct Foo(pub i32, pub i32);
455
456            //- /main.rs crate:main deps:dep
457            fn main(foo: dep::Foo) {
458                let $0foo2 = foo;
459                let bar = foo2.0;
460                let baz = foo2.1;
461            }
462            "#,
463        )
464    }
465
466    #[test]
467    fn non_exhaustive_unit_not_applicable() {
468        check_assist_not_applicable(
469            destructure_struct_binding,
470            r#"
471            //- /lib.rs crate:dep
472            #[non_exhaustive]
473            pub struct Foo;
474
475            //- /main.rs crate:main deps:dep
476            fn main(foo: dep::Foo) {
477                let $0foo2 = foo;
478            }
479            "#,
480        )
481    }
482
483    #[test]
484    fn record_private_fields_appends_rest() {
485        check_assist(
486            destructure_struct_binding,
487            r#"
488            //- /lib.rs crate:dep
489            pub struct Foo { pub bar: i32, baz: i32 };
490
491            //- /main.rs crate:main deps:dep
492            fn main(foo: dep::Foo) {
493                let $0foo2 = foo;
494                let bar2 = foo2.bar;
495            }
496            "#,
497            r#"
498            fn main(foo: dep::Foo) {
499                let dep::Foo { bar, .. } = foo;
500                let bar2 = bar;
501            }
502            "#,
503        )
504    }
505
506    #[test]
507    fn tuple_private_fields_not_applicable() {
508        check_assist_not_applicable(
509            destructure_struct_binding,
510            r#"
511            //- /lib.rs crate:dep
512            pub struct Foo(pub i32, i32);
513
514            //- /main.rs crate:main deps:dep
515            fn main(foo: dep::Foo) {
516                let $0foo2 = foo;
517                let bar2 = foo2.0;
518            }
519            "#,
520        )
521    }
522
523    #[test]
524    fn nested_inside_record() {
525        check_assist(
526            destructure_struct_binding,
527            r#"
528            struct Foo { fizz: Fizz }
529            struct Fizz { buzz: i32 }
530
531            fn main() {
532                let Foo { $0fizz } = Foo { fizz: Fizz { buzz: 1 } };
533                let buzz2 = fizz.buzz;
534            }
535            "#,
536            r#"
537            struct Foo { fizz: Fizz }
538            struct Fizz { buzz: i32 }
539
540            fn main() {
541                let Foo { fizz: Fizz { buzz } } = Foo { fizz: Fizz { buzz: 1 } };
542                let buzz2 = buzz;
543            }
544            "#,
545        )
546    }
547
548    #[test]
549    fn nested_inside_tuple() {
550        check_assist(
551            destructure_struct_binding,
552            r#"
553            struct Foo(Fizz);
554            struct Fizz { buzz: i32 }
555
556            fn main() {
557                let Foo($0fizz) = Foo(Fizz { buzz: 1 });
558                let buzz2 = fizz.buzz;
559            }
560            "#,
561            r#"
562            struct Foo(Fizz);
563            struct Fizz { buzz: i32 }
564
565            fn main() {
566                let Foo(Fizz { buzz }) = Foo(Fizz { buzz: 1 });
567                let buzz2 = buzz;
568            }
569            "#,
570        )
571    }
572
573    #[test]
574    fn mut_record() {
575        check_assist(
576            destructure_struct_binding,
577            r#"
578            struct Foo { bar: i32, baz: i32 }
579
580            fn main() {
581                let mut $0foo = Foo { bar: 1, baz: 2 };
582                let bar2 = foo.bar;
583                let baz2 = &foo.baz;
584            }
585            "#,
586            r#"
587            struct Foo { bar: i32, baz: i32 }
588
589            fn main() {
590                let Foo { mut bar, mut baz } = Foo { bar: 1, baz: 2 };
591                let bar2 = bar;
592                let baz2 = &baz;
593            }
594            "#,
595        )
596    }
597
598    #[test]
599    fn mut_record_field() {
600        check_assist(
601            destructure_struct_binding,
602            r#"
603            struct Foo { x: () }
604            struct Bar { foo: Foo }
605            fn f(Bar { mut $0foo }: Bar) {}
606            "#,
607            r#"
608            struct Foo { x: () }
609            struct Bar { foo: Foo }
610            fn f(Bar { foo: Foo { mut x } }: Bar) {}
611            "#,
612        )
613    }
614
615    #[test]
616    fn ref_record_field() {
617        check_assist(
618            destructure_struct_binding,
619            r#"
620            struct Foo { x: () }
621            struct Bar { foo: Foo }
622            fn f(Bar { ref $0foo }: Bar) {
623                let _ = foo.x;
624            }
625            "#,
626            r#"
627            struct Foo { x: () }
628            struct Bar { foo: Foo }
629            fn f(Bar { foo: Foo { ref x } }: Bar) {
630                let _ = *x;
631            }
632            "#,
633        )
634    }
635
636    #[test]
637    fn ref_mut_record_field() {
638        check_assist(
639            destructure_struct_binding,
640            r#"
641            struct Foo { x: () }
642            struct Bar { foo: Foo }
643            fn f(Bar { ref mut $0foo }: Bar) {
644                let _ = foo.x;
645            }
646            "#,
647            r#"
648            struct Foo { x: () }
649            struct Bar { foo: Foo }
650            fn f(Bar { foo: Foo { ref mut x } }: Bar) {
651                let _ = *x;
652            }
653            "#,
654        )
655    }
656
657    #[test]
658    fn ref_mut_record_renamed_field() {
659        check_assist(
660            destructure_struct_binding,
661            r#"
662            struct Foo { x: () }
663            struct Bar { foo: Foo }
664            fn f(Bar { foo: ref mut $0foo1 }: Bar) {
665                let _ = foo1.x;
666            }
667            "#,
668            r#"
669            struct Foo { x: () }
670            struct Bar { foo: Foo }
671            fn f(Bar { foo: Foo { ref mut x } }: Bar) {
672                let _ = *x;
673            }
674            "#,
675        )
676    }
677
678    #[test]
679    fn mut_ref() {
680        check_assist(
681            destructure_struct_binding,
682            r#"
683            struct Foo { bar: i32, baz: i32 }
684
685            fn main() {
686                let $0foo = &mut Foo { bar: 1, baz: 2 };
687                foo.bar = 5;
688            }
689            "#,
690            r#"
691            struct Foo { bar: i32, baz: i32 }
692
693            fn main() {
694                let Foo { bar, baz } = &mut Foo { bar: 1, baz: 2 };
695                *bar = 5;
696            }
697            "#,
698        )
699    }
700
701    #[test]
702    fn ref_not_add_parenthesis_and_deref_record() {
703        check_assist(
704            destructure_struct_binding,
705            r#"
706            struct Foo { bar: i32, baz: i32 }
707
708            fn main() {
709                let $0foo = &Foo { bar: 1, baz: 2 };
710                let _ = &foo.bar;
711            }
712            "#,
713            r#"
714            struct Foo { bar: i32, baz: i32 }
715
716            fn main() {
717                let Foo { bar, baz } = &Foo { bar: 1, baz: 2 };
718                let _ = bar;
719            }
720            "#,
721        )
722    }
723
724    #[test]
725    fn ref_not_add_parenthesis_and_deref_tuple() {
726        check_assist(
727            destructure_struct_binding,
728            r#"
729            struct Foo(i32, i32);
730
731            fn main() {
732                let $0foo = &Foo(1, 2);
733                let _ = &foo.0;
734            }
735            "#,
736            r#"
737            struct Foo(i32, i32);
738
739            fn main() {
740                let Foo(_0, _1) = &Foo(1, 2);
741                let _ = _0;
742            }
743            "#,
744        )
745    }
746
747    #[test]
748    fn record_struct_name_collision() {
749        check_assist(
750            destructure_struct_binding,
751            r#"
752            struct Foo { bar: i32, baz: i32 }
753
754            fn main(baz: i32) {
755                let bar = true;
756                let $0foo = Foo { bar: 1, baz: 2 };
757                let baz_1 = 7;
758                let bar_usage = foo.bar;
759                let baz_usage = foo.baz;
760            }
761            "#,
762            r#"
763            struct Foo { bar: i32, baz: i32 }
764
765            fn main(baz: i32) {
766                let bar = true;
767                let Foo { bar: bar_1, baz: baz_2 } = Foo { bar: 1, baz: 2 };
768                let baz_1 = 7;
769                let bar_usage = bar_1;
770                let baz_usage = baz_2;
771            }
772            "#,
773        )
774    }
775
776    #[test]
777    fn tuple_struct_name_collision() {
778        check_assist(
779            destructure_struct_binding,
780            r#"
781            struct Foo(i32, i32);
782
783            fn main() {
784                let _0 = true;
785                let $0foo = Foo(1, 2);
786                let bar = foo.0;
787                let baz = foo.1;
788            }
789            "#,
790            r#"
791            struct Foo(i32, i32);
792
793            fn main() {
794                let _0 = true;
795                let Foo(_0_1, _1) = Foo(1, 2);
796                let bar = _0_1;
797                let baz = _1;
798            }
799            "#,
800        )
801    }
802
803    #[test]
804    fn record_struct_name_collision_nested_scope() {
805        check_assist(
806            destructure_struct_binding,
807            r#"
808            struct Foo { bar: i32 }
809
810            fn main(foo: Foo) {
811                let bar = 5;
812
813                let new_bar = {
814                    let $0foo2 = foo;
815                    let bar_1 = 5;
816                    foo2.bar
817                };
818            }
819            "#,
820            r#"
821            struct Foo { bar: i32 }
822
823            fn main(foo: Foo) {
824                let bar = 5;
825
826                let new_bar = {
827                    let Foo { bar: bar_2 } = foo;
828                    let bar_1 = 5;
829                    bar_2
830                };
831            }
832            "#,
833        )
834    }
835
836    #[test]
837    fn record_struct_no_public_members() {
838        check_assist_not_applicable(
839            destructure_struct_binding,
840            r#"
841            //- /lib.rs crate:dep
842            pub struct Foo { bar: i32, baz: i32 };
843
844            //- /main.rs crate:main deps:dep
845            fn main($0foo: dep::Foo) {}
846            "#,
847        )
848    }
849}