# Proposal
## Problem statement
It seems like there is a common use-case t…o 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:
<details><summary>list</summary>
<p>
```
:~/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()) {
```
</p>
</details>
## Solution sketches
```rust
impl<T> Option<T> {
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