-   Notifications  
You must be signed in to change notification settings  - Fork 24
 
Description
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 tracking issue:
- Tracking Issue for Option::is_some_and and Result::is_{ok,err}_and rust#93050 (comment)
 - Tracking Issue for Option::is_some_and and Result::is_{ok,err}_and rust#93050 (comment)
 - Tracking Issue for Option::is_some_and and Result::is_{ok,err}_and rust#93050 (comment)
 - Tracking Issue for Option::is_some_and and Result::is_{ok,err}_and rust#93050 (comment)
 
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
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: rust-lang/rust#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.