# Proposal ## Problem statement It seems like there is a common use-case to check if an option is `None` or some condition holds for its value. ## Motivation, use-cases Similarly to how we have `Option::is_some_and` which is basically `.map_or(false, ...)`, sometimes it is desirable to have the opposite "default" value, i.e. sometimes a better name for `.map_or(true, ...)` is wanted. See for example comments on the [`Option::is_some_and`](https://github.com/rust-lang/rust/issues/93050) tracking issue: - https://github.com/rust-lang/rust/issues/93050#issuecomment-1151881604 - https://github.com/rust-lang/rust/issues/93050#issuecomment-1160253211 - https://github.com/rust-lang/rust/issues/93050#issuecomment-1164666533 - https://github.com/rust-lang/rust/issues/93050#issuecomment-1180638364 See also 45 occurrences of `.map_or(true, ...)` in the rustc itself: list ``` :~/rust-lib (rust-lib); rg ".map_or\(true" ./compiler --stats -q | rg "\d+ matches" 45 matches :~/rust-lib (rust-lib); rg ".map_or\(true" ./compiler ./compiler/rustc_middle/src/values.rs 180: let check_params = def_id.as_local().map_or(true, |def_id| { ./compiler/rustc_middle/src/ty/instance.rs 236: return ty.ty_adt_def().map_or(true, |adt_def| { ./compiler/rustc_session/src/parse.rs 58: self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty()) ./compiler/rustc_passes/src/dead.rs 682: .map_or(true, |layout| layout.is_zst()) ./compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs 152: .map_or(true, |overlap| { ./compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs 72: if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") { ./compiler/rustc_hir_analysis/src/check_unused.rs 79: tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| { ./compiler/rustc_attr/src/builtin.rs 1092: if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { ./compiler/rustc_resolve/src/macros.rs 840: if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) { ./compiler/rustc_resolve/src/imports.rs 249: || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self)) ./compiler/rustc_parse/src/parser/attr.rs 428: attr.ident().map_or(true, |ident| { ./compiler/rustc_resolve/src/lib.rs 1066: if def_id.map_or(true, |def_id| def_id.is_local()) { ./compiler/rustc_resolve/src/diagnostics.rs 285: self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item); 512: if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) { ./compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs 1463: .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) 1499: && last_ty.map_or(true, |last_ty| { ./compiler/rustc_infer/src/infer/mod.rs 1474: value.as_ref().map_or(true, |value| !value.needs_infer()), ./compiler/rustc_mir_dataflow/src/framework/graphviz.rs 416: assert!(befores.as_ref().map_or(true, ExactSizeIterator::is_empty)); ./compiler/rustc_mir_dataflow/src/framework/direction.rs 290: if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { 505: if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { 537: if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { 563: if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { ./compiler/rustc_hir_typeck/src/_match.rs 155: && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty)) ./compiler/rustc_hir_typeck/src/lib.rs 490: trait_did.map_or(true, |trait_did| { ./compiler/rustc_hir_typeck/src/expr.rs 1458: if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { ./compiler/rustc_hir_typeck/src/coercion.rs 947: .map_or(true, |u| u.is_empty()) => ./compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs 992: .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) ./compiler/rustc_hir_typeck/src/generator_interior/mod.rs 396: || ty.map_or(true, |ty| { ./compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs 2190: .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) ./compiler/rustc_hir/src/def.rs 729: self.ns().map_or(true, |actual_ns| actual_ns == ns) ./compiler/rustc_index/src/interval.rs 234: current.map_or(true, |x| x < self.domain as u32) ./compiler/rustc_expand/src/config.rs 466: parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| { 474: if !self.features.map_or(true, |features| features.stmt_expr_attributes) { ./compiler/rustc_const_eval/src/interpret/util.rs 44: let is_used = unused_params.contains(index).map_or(true, |unused| !unused); ./compiler/rustc_const_eval/src/interpret/intern.rs 117: let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env)); ./compiler/rustc_const_eval/src/interpret/memory.rs 431: if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { ./compiler/rustc_const_eval/src/interpret/projection.rs 295: if from.checked_add(to).map_or(true, |to| to > len) { ./compiler/rustc_mir_transform/src/const_prop_lint.rs 722: .map_or(true, |layout| layout.is_zst()) ./compiler/rustc_mir_transform/src/coverage/graph.rs 387: if !self.counter_kind.as_ref().map_or(true, |c| c.is_expression()) { ./compiler/rustc_mir_transform/src/const_prop.rs 1142: .map_or(true, |layout| layout.is_zst()) ./compiler/rustc_mir_transform/src/coverage/spans.rs 484: if self.prev_expn_span.map_or(true, |prev_expn_span| { ./compiler/rustc_mir_build/src/check_unsafety.rs 172: ref kind if ExprCategory::of(kind).map_or(true, |cat| cat == ExprCategory::Place) => { ./compiler/rustc_borrowck/src/type_check/mod.rs 1892: if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { ./compiler/rustc_lint/src/expect.rs 29: && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) ./compiler/rustc_ast_passes/src/feature_gate.rs 100: if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { ``` ## Solution sketches ```rust impl Option { pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { match self { None => true, Some(x) => f(x), } } } ``` ## Links and related work There is an open PR implementing this, that was untouched for 8 moths: https://github.com/rust-lang/rust/pull/100602 ## What happens now? This issue is part of the libs-api team [API change proposal process]. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two. [API change proposal process]: https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html