datafusion_physical_expr_common/sort_expr.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Sort expressions
19
20use std::cmp::Ordering;
21use std::fmt::{self, Display, Formatter};
22use std::hash::{Hash, Hasher};
23use std::ops::{Deref, DerefMut};
24use std::sync::Arc;
25use std::vec::IntoIter;
26
27use crate::physical_expr::{fmt_sql, PhysicalExpr};
28
29use arrow::compute::kernels::sort::{SortColumn, SortOptions};
30use arrow::datatypes::Schema;
31use arrow::record_batch::RecordBatch;
32use datafusion_common::{HashSet, Result};
33use datafusion_expr_common::columnar_value::ColumnarValue;
34
35/// Represents Sort operation for a column in a RecordBatch
36///
37/// Example:
38/// ```
39/// # use std::any::Any;
40/// # use std::collections::HashMap;
41/// # use std::fmt::{Display, Formatter};
42/// # use std::hash::Hasher;
43/// # use std::sync::Arc;
44/// # use arrow::array::RecordBatch;
45/// # use datafusion_common::Result;
46/// # use arrow::compute::SortOptions;
47/// # use arrow::datatypes::{DataType, Field, FieldRef, Schema};
48/// # use datafusion_expr_common::columnar_value::ColumnarValue;
49/// # use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
50/// # use datafusion_physical_expr_common::sort_expr::PhysicalSortExpr;
51/// # // this crate doesn't have a physical expression implementation
52/// # // so make a really simple one
53/// # #[derive(Clone, Debug, PartialEq, Eq, Hash)]
54/// # struct MyPhysicalExpr;
55/// # impl PhysicalExpr for MyPhysicalExpr {
56/// # fn as_any(&self) -> &dyn Any {todo!() }
57/// # fn data_type(&self, input_schema: &Schema) -> Result<DataType> {todo!()}
58/// # fn nullable(&self, input_schema: &Schema) -> Result<bool> {todo!() }
59/// # fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {todo!() }
60/// # fn return_field(&self, input_schema: &Schema) -> Result<FieldRef> { unimplemented!() }
61/// # fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {todo!()}
62/// # fn with_new_children(self: Arc<Self>, children: Vec<Arc<dyn PhysicalExpr>>) -> Result<Arc<dyn PhysicalExpr>> {todo!()}
63/// # fn fmt_sql(&self, f: &mut Formatter<'_>) -> std::fmt::Result { todo!() }
64/// # }
65/// # impl Display for MyPhysicalExpr {
66/// # fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "a") }
67/// # }
68/// # fn col(name: &str) -> Arc<dyn PhysicalExpr> { Arc::new(MyPhysicalExpr) }
69/// // Sort by a ASC
70/// let options = SortOptions::default();
71/// let sort_expr = PhysicalSortExpr::new(col("a"), options);
72/// assert_eq!(sort_expr.to_string(), "a ASC");
73///
74/// // Sort by a DESC NULLS LAST
75/// let sort_expr = PhysicalSortExpr::new_default(col("a"))
76/// .desc()
77/// .nulls_last();
78/// assert_eq!(sort_expr.to_string(), "a DESC NULLS LAST");
79/// ```
80#[derive(Clone, Debug, Eq)]
81pub struct PhysicalSortExpr {
82 /// Physical expression representing the column to sort
83 pub expr: Arc<dyn PhysicalExpr>,
84 /// Option to specify how the given column should be sorted
85 pub options: SortOptions,
86}
87
88impl PhysicalSortExpr {
89 /// Create a new PhysicalSortExpr
90 pub fn new(expr: Arc<dyn PhysicalExpr>, options: SortOptions) -> Self {
91 Self { expr, options }
92 }
93
94 /// Create a new PhysicalSortExpr with default [`SortOptions`]
95 pub fn new_default(expr: Arc<dyn PhysicalExpr>) -> Self {
96 Self::new(expr, SortOptions::default())
97 }
98
99 /// Reverses the sort expression. For instance, `[a ASC NULLS LAST]` turns
100 /// into `[a DESC NULLS FIRST]`. Such reversals are useful in planning, e.g.
101 /// when constructing equivalent window expressions.
102 pub fn reverse(&self) -> Self {
103 let mut result = self.clone();
104 result.options = !result.options;
105 result
106 }
107
108 /// Set the sort sort options to ASC
109 pub fn asc(mut self) -> Self {
110 self.options.descending = false;
111 self
112 }
113
114 /// Set the sort sort options to DESC
115 pub fn desc(mut self) -> Self {
116 self.options.descending = true;
117 self
118 }
119
120 /// Set the sort sort options to NULLS FIRST
121 pub fn nulls_first(mut self) -> Self {
122 self.options.nulls_first = true;
123 self
124 }
125
126 /// Set the sort sort options to NULLS LAST
127 pub fn nulls_last(mut self) -> Self {
128 self.options.nulls_first = false;
129 self
130 }
131
132 /// Like [`PhysicalExpr::fmt_sql`] prints a [`PhysicalSortExpr`] in a SQL-like format.
133 pub fn fmt_sql(&self, f: &mut Formatter) -> fmt::Result {
134 write!(
135 f,
136 "{} {}",
137 fmt_sql(self.expr.as_ref()),
138 to_str(&self.options)
139 )
140 }
141
142 /// Evaluates the sort expression into a `SortColumn` that can be passed
143 /// into the arrow sort kernel.
144 pub fn evaluate_to_sort_column(&self, batch: &RecordBatch) -> Result<SortColumn> {
145 let array_to_sort = match self.expr.evaluate(batch)? {
146 ColumnarValue::Array(array) => array,
147 ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(batch.num_rows())?,
148 };
149 Ok(SortColumn {
150 values: array_to_sort,
151 options: Some(self.options),
152 })
153 }
154
155 /// Checks whether this sort expression satisfies the given `requirement`.
156 /// If sort options are unspecified in `requirement`, only expressions are
157 /// compared for inequality. See [`options_compatible`] for details on
158 /// how sort options compare with one another.
159 pub fn satisfy(
160 &self,
161 requirement: &PhysicalSortRequirement,
162 schema: &Schema,
163 ) -> bool {
164 self.expr.eq(&requirement.expr)
165 && requirement.options.is_none_or(|opts| {
166 options_compatible(
167 &self.options,
168 &opts,
169 self.expr.nullable(schema).unwrap_or(true),
170 )
171 })
172 }
173
174 /// Checks whether this sort expression satisfies the given `sort_expr`.
175 /// See [`options_compatible`] for details on how sort options compare with
176 /// one another.
177 pub fn satisfy_expr(&self, sort_expr: &Self, schema: &Schema) -> bool {
178 self.expr.eq(&sort_expr.expr)
179 && options_compatible(
180 &self.options,
181 &sort_expr.options,
182 self.expr.nullable(schema).unwrap_or(true),
183 )
184 }
185}
186
187impl PartialEq for PhysicalSortExpr {
188 fn eq(&self, other: &Self) -> bool {
189 self.options == other.options && self.expr.eq(&other.expr)
190 }
191}
192
193impl Hash for PhysicalSortExpr {
194 fn hash<H: Hasher>(&self, state: &mut H) {
195 self.expr.hash(state);
196 self.options.hash(state);
197 }
198}
199
200impl Display for PhysicalSortExpr {
201 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
202 write!(f, "{} {}", self.expr, to_str(&self.options))
203 }
204}
205
206/// Returns whether the given two [`SortOptions`] are compatible. Here,
207/// compatibility means that they are either exactly equal, or they differ only
208/// in whether NULL values come in first/last, which is immaterial because the
209/// column in question is not nullable (specified by the `nullable` parameter).
210pub fn options_compatible(
211 options_lhs: &SortOptions,
212 options_rhs: &SortOptions,
213 nullable: bool,
214) -> bool {
215 if nullable {
216 options_lhs == options_rhs
217 } else {
218 // If the column is not nullable, NULLS FIRST/LAST is not important.
219 options_lhs.descending == options_rhs.descending
220 }
221}
222
223/// Represents sort requirement associated with a plan
224///
225/// If the requirement includes [`SortOptions`] then both the
226/// expression *and* the sort options must match.
227///
228/// If the requirement does not include [`SortOptions`]) then only the
229/// expressions must match.
230///
231/// # Examples
232///
233/// With sort options (`A`, `DESC NULLS FIRST`):
234/// * `ORDER BY A DESC NULLS FIRST` matches
235/// * `ORDER BY A ASC NULLS FIRST` does not match (`ASC` vs `DESC`)
236/// * `ORDER BY B DESC NULLS FIRST` does not match (different expr)
237///
238/// Without sort options (`A`, None):
239/// * `ORDER BY A DESC NULLS FIRST` matches
240/// * `ORDER BY A ASC NULLS FIRST` matches (`ASC` and `NULL` options ignored)
241/// * `ORDER BY B DESC NULLS FIRST` does not match (different expr)
242#[derive(Clone, Debug)]
243pub struct PhysicalSortRequirement {
244 /// Physical expression representing the column to sort
245 pub expr: Arc<dyn PhysicalExpr>,
246 /// Option to specify how the given column should be sorted.
247 /// If unspecified, there are no constraints on sort options.
248 pub options: Option<SortOptions>,
249}
250
251impl PartialEq for PhysicalSortRequirement {
252 fn eq(&self, other: &Self) -> bool {
253 self.options == other.options && self.expr.eq(&other.expr)
254 }
255}
256
257impl Display for PhysicalSortRequirement {
258 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
259 let opts_string = self.options.as_ref().map_or("NA", to_str);
260 write!(f, "{} {}", self.expr, opts_string)
261 }
262}
263
264/// Writes a list of [`PhysicalSortRequirement`]s to a `std::fmt::Formatter`.
265///
266/// Example output: `[a + 1, b]`
267pub fn format_physical_sort_requirement_list(
268 exprs: &[PhysicalSortRequirement],
269) -> impl Display + '_ {
270 struct DisplayWrapper<'a>(&'a [PhysicalSortRequirement]);
271 impl Display for DisplayWrapper<'_> {
272 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
273 let mut iter = self.0.iter();
274 write!(f, "[")?;
275 if let Some(expr) = iter.next() {
276 write!(f, "{expr}")?;
277 }
278 for expr in iter {
279 write!(f, ", {expr}")?;
280 }
281 write!(f, "]")?;
282 Ok(())
283 }
284 }
285 DisplayWrapper(exprs)
286}
287
288impl PhysicalSortRequirement {
289 /// Creates a new requirement.
290 ///
291 /// If `options` is `Some(..)`, creates an `exact` requirement,
292 /// which must match both `options` and `expr`.
293 ///
294 /// If `options` is `None`, Creates a new `expr_only` requirement,
295 /// which must match only `expr`.
296 ///
297 /// See [`PhysicalSortRequirement`] for examples.
298 pub fn new(expr: Arc<dyn PhysicalExpr>, options: Option<SortOptions>) -> Self {
299 Self { expr, options }
300 }
301
302 /// Returns whether this requirement is equal or more specific than `other`.
303 pub fn compatible(&self, other: &Self) -> bool {
304 self.expr.eq(&other.expr)
305 && other
306 .options
307 .is_none_or(|other_opts| self.options == Some(other_opts))
308 }
309}
310
311/// Returns the SQL string representation of the given [`SortOptions`] object.
312#[inline]
313fn to_str(options: &SortOptions) -> &str {
314 match (options.descending, options.nulls_first) {
315 (true, true) => "DESC",
316 (true, false) => "DESC NULLS LAST",
317 (false, true) => "ASC",
318 (false, false) => "ASC NULLS LAST",
319 }
320}
321
322// Cross-conversion utilities between `PhysicalSortExpr` and `PhysicalSortRequirement`
323impl From<PhysicalSortExpr> for PhysicalSortRequirement {
324 fn from(value: PhysicalSortExpr) -> Self {
325 Self::new(value.expr, Some(value.options))
326 }
327}
328
329impl From<PhysicalSortRequirement> for PhysicalSortExpr {
330 /// The default sort options `ASC, NULLS LAST` when the requirement does
331 /// not specify sort options. This default is consistent with PostgreSQL.
332 ///
333 /// Reference: <https://www.postgresql.org/docs/current/queries-order.html>
334 fn from(value: PhysicalSortRequirement) -> Self {
335 let options = value
336 .options
337 .unwrap_or_else(|| SortOptions::new(false, false));
338 Self::new(value.expr, options)
339 }
340}
341
342/// This object represents a lexicographical ordering and contains a vector
343/// of `PhysicalSortExpr` objects.
344///
345/// For example, a `vec![a ASC, b DESC]` represents a lexicographical ordering
346/// that first sorts by column `a` in ascending order, then by column `b` in
347/// descending order.
348///
349/// # Invariants
350///
351/// The following always hold true for a `LexOrdering`:
352///
353/// 1. It is non-degenerate, meaning it contains at least one element.
354/// 2. It is duplicate-free, meaning it does not contain multiple entries for
355/// the same column.
356#[derive(Debug, Clone, PartialEq, Eq)]
357pub struct LexOrdering {
358 /// Vector of sort expressions representing the lexicographical ordering.
359 exprs: Vec<PhysicalSortExpr>,
360 /// Set of expressions in the lexicographical ordering, used to ensure
361 /// that the ordering is duplicate-free. Note that the elements in this
362 /// set are the same underlying physical expressions as in `exprs`.
363 set: HashSet<Arc<dyn PhysicalExpr>>,
364}
365
366impl LexOrdering {
367 /// Creates a new [`LexOrdering`] from the given vector of sort expressions.
368 /// If the vector is empty, returns `None`.
369 pub fn new(exprs: impl IntoIterator<Item = PhysicalSortExpr>) -> Option<Self> {
370 let (non_empty, ordering) = Self::construct(exprs);
371 non_empty.then_some(ordering)
372 }
373
374 /// Appends an element to the back of the `LexOrdering`.
375 pub fn push(&mut self, sort_expr: PhysicalSortExpr) {
376 if self.set.insert(Arc::clone(&sort_expr.expr)) {
377 self.exprs.push(sort_expr);
378 }
379 }
380
381 /// Add all elements from `iter` to the `LexOrdering`.
382 pub fn extend(&mut self, sort_exprs: impl IntoIterator<Item = PhysicalSortExpr>) {
383 for sort_expr in sort_exprs {
384 self.push(sort_expr);
385 }
386 }
387
388 /// Returns the leading `PhysicalSortExpr` of the `LexOrdering`. Note that
389 /// this function does not return an `Option`, as a `LexOrdering` is always
390 /// non-degenerate (i.e. it contains at least one element).
391 pub fn first(&self) -> &PhysicalSortExpr {
392 // Can safely `unwrap` because `LexOrdering` is non-degenerate:
393 self.exprs.first().unwrap()
394 }
395
396 /// Returns the number of elements that can be stored in the `LexOrdering`
397 /// without reallocating.
398 pub fn capacity(&self) -> usize {
399 self.exprs.capacity()
400 }
401
402 /// Truncates the `LexOrdering`, keeping only the first `len` elements.
403 /// Returns `true` if truncation made a change, `false` otherwise. Negative
404 /// cases happen in two scenarios: (1) When `len` is greater than or equal
405 /// to the number of expressions inside this `LexOrdering`, making truncation
406 /// a no-op, or (2) when `len` is `0`, making truncation impossible.
407 pub fn truncate(&mut self, len: usize) -> bool {
408 if len == 0 || len >= self.exprs.len() {
409 return false;
410 }
411 for PhysicalSortExpr { expr, .. } in self.exprs[len..].iter() {
412 self.set.remove(expr);
413 }
414 self.exprs.truncate(len);
415 true
416 }
417
418 /// Constructs a new `LexOrdering` from the given sort requirements w/o
419 /// enforcing non-degeneracy. This function is used internally and is not
420 /// meant (or safe) for external use.
421 fn construct(exprs: impl IntoIterator<Item = PhysicalSortExpr>) -> (bool, Self) {
422 let mut set = HashSet::new();
423 let exprs = exprs
424 .into_iter()
425 .filter_map(|s| set.insert(Arc::clone(&s.expr)).then_some(s))
426 .collect();
427 (!set.is_empty(), Self { exprs, set })
428 }
429}
430
431impl PartialOrd for LexOrdering {
432 /// There is a partial ordering among `LexOrdering` objects. For example, the
433 /// ordering `[a ASC]` is coarser (less) than ordering `[a ASC, b ASC]`.
434 /// If two orderings do not share a prefix, they are incomparable.
435 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
436 self.iter()
437 .zip(other.iter())
438 .all(|(lhs, rhs)| lhs == rhs)
439 .then(|| self.len().cmp(&other.len()))
440 }
441}
442
443impl<const N: usize> From<[PhysicalSortExpr; N]> for LexOrdering {
444 fn from(value: [PhysicalSortExpr; N]) -> Self {
445 // TODO: Replace this assertion with a condition on the generic parameter
446 // when Rust supports it.
447 assert!(N > 0);
448 let (non_empty, ordering) = Self::construct(value);
449 debug_assert!(non_empty);
450 ordering
451 }
452}
453
454impl Deref for LexOrdering {
455 type Target = [PhysicalSortExpr];
456
457 fn deref(&self) -> &Self::Target {
458 self.exprs.as_slice()
459 }
460}
461
462impl Display for LexOrdering {
463 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
464 let mut first = true;
465 for sort_expr in &self.exprs {
466 if first {
467 first = false;
468 } else {
469 write!(f, ", ")?;
470 }
471 write!(f, "{sort_expr}")?;
472 }
473 Ok(())
474 }
475}
476
477impl IntoIterator for LexOrdering {
478 type Item = PhysicalSortExpr;
479 type IntoIter = IntoIter<Self::Item>;
480
481 fn into_iter(self) -> Self::IntoIter {
482 self.exprs.into_iter()
483 }
484}
485
486impl<'a> IntoIterator for &'a LexOrdering {
487 type Item = &'a PhysicalSortExpr;
488 type IntoIter = std::slice::Iter<'a, PhysicalSortExpr>;
489
490 fn into_iter(self) -> Self::IntoIter {
491 self.exprs.iter()
492 }
493}
494
495impl From<LexOrdering> for Vec<PhysicalSortExpr> {
496 fn from(ordering: LexOrdering) -> Self {
497 ordering.exprs
498 }
499}
500
501/// This object represents a lexicographical ordering requirement and contains
502/// a vector of `PhysicalSortRequirement` objects.
503///
504/// For example, a `vec![a Some(ASC), b None]` represents a lexicographical
505/// requirement that firsts imposes an ordering by column `a` in ascending
506/// order, then by column `b` in *any* (ascending or descending) order. The
507/// ordering is non-degenerate, meaning it contains at least one element, and
508/// it is duplicate-free, meaning it does not contain multiple entries for the
509/// same column.
510///
511/// Note that a `LexRequirement` need not enforce the uniqueness of its sort
512/// expressions after construction like a `LexOrdering` does, because it provides
513/// no mutation methods. If such methods become necessary, we will need to
514/// enforce uniqueness like the latter object.
515#[derive(Debug, Clone, PartialEq)]
516pub struct LexRequirement {
517 reqs: Vec<PhysicalSortRequirement>,
518}
519
520impl LexRequirement {
521 /// Creates a new [`LexRequirement`] from the given vector of sort expressions.
522 /// If the vector is empty, returns `None`.
523 pub fn new(reqs: impl IntoIterator<Item = PhysicalSortRequirement>) -> Option<Self> {
524 let (non_empty, requirements) = Self::construct(reqs);
525 non_empty.then_some(requirements)
526 }
527
528 /// Returns the leading `PhysicalSortRequirement` of the `LexRequirement`.
529 /// Note that this function does not return an `Option`, as a `LexRequirement`
530 /// is always non-degenerate (i.e. it contains at least one element).
531 pub fn first(&self) -> &PhysicalSortRequirement {
532 // Can safely `unwrap` because `LexRequirement` is non-degenerate:
533 self.reqs.first().unwrap()
534 }
535
536 /// Constructs a new `LexRequirement` from the given sort requirements w/o
537 /// enforcing non-degeneracy. This function is used internally and is not
538 /// meant (or safe) for external use.
539 fn construct(
540 reqs: impl IntoIterator<Item = PhysicalSortRequirement>,
541 ) -> (bool, Self) {
542 let mut set = HashSet::new();
543 let reqs = reqs
544 .into_iter()
545 .filter_map(|r| set.insert(Arc::clone(&r.expr)).then_some(r))
546 .collect();
547 (!set.is_empty(), Self { reqs })
548 }
549}
550
551impl<const N: usize> From<[PhysicalSortRequirement; N]> for LexRequirement {
552 fn from(value: [PhysicalSortRequirement; N]) -> Self {
553 // TODO: Replace this assertion with a condition on the generic parameter
554 // when Rust supports it.
555 assert!(N > 0);
556 let (non_empty, requirement) = Self::construct(value);
557 debug_assert!(non_empty);
558 requirement
559 }
560}
561
562impl Deref for LexRequirement {
563 type Target = [PhysicalSortRequirement];
564
565 fn deref(&self) -> &Self::Target {
566 self.reqs.as_slice()
567 }
568}
569
570impl IntoIterator for LexRequirement {
571 type Item = PhysicalSortRequirement;
572 type IntoIter = IntoIter<Self::Item>;
573
574 fn into_iter(self) -> Self::IntoIter {
575 self.reqs.into_iter()
576 }
577}
578
579impl<'a> IntoIterator for &'a LexRequirement {
580 type Item = &'a PhysicalSortRequirement;
581 type IntoIter = std::slice::Iter<'a, PhysicalSortRequirement>;
582
583 fn into_iter(self) -> Self::IntoIter {
584 self.reqs.iter()
585 }
586}
587
588impl From<LexRequirement> for Vec<PhysicalSortRequirement> {
589 fn from(requirement: LexRequirement) -> Self {
590 requirement.reqs
591 }
592}
593
594// Cross-conversion utilities between `LexOrdering` and `LexRequirement`
595impl From<LexOrdering> for LexRequirement {
596 fn from(value: LexOrdering) -> Self {
597 // Can construct directly as `value` is non-degenerate:
598 let (non_empty, requirements) =
599 Self::construct(value.into_iter().map(Into::into));
600 debug_assert!(non_empty);
601 requirements
602 }
603}
604
605impl From<LexRequirement> for LexOrdering {
606 fn from(value: LexRequirement) -> Self {
607 // Can construct directly as `value` is non-degenerate:
608 let (non_empty, ordering) = Self::construct(value.into_iter().map(Into::into));
609 debug_assert!(non_empty);
610 ordering
611 }
612}
613
614/// Represents a plan's input ordering requirements. Vector elements represent
615/// alternative ordering requirements in the order of preference. The list of
616/// alternatives can be either hard or soft, depending on whether the operator
617/// can work without an input ordering.
618///
619/// # Invariants
620///
621/// The following always hold true for a `OrderingRequirements`:
622///
623/// 1. It is non-degenerate, meaning it contains at least one ordering. The
624/// absence of an input ordering requirement is represented by a `None` value
625/// in `ExecutionPlan` APIs, which return an `Option<OrderingRequirements>`.
626#[derive(Debug, Clone, PartialEq)]
627pub enum OrderingRequirements {
628 /// The operator is not able to work without one of these requirements.
629 Hard(Vec<LexRequirement>),
630 /// The operator can benefit from these input orderings when available,
631 /// but can still work in the absence of any input ordering.
632 Soft(Vec<LexRequirement>),
633}
634
635impl OrderingRequirements {
636 /// Creates a new instance from the given alternatives. If an empty list of
637 /// alternatives are given, returns `None`.
638 pub fn new_alternatives(
639 alternatives: impl IntoIterator<Item = LexRequirement>,
640 soft: bool,
641 ) -> Option<Self> {
642 let alternatives = alternatives.into_iter().collect::<Vec<_>>();
643 (!alternatives.is_empty()).then(|| {
644 if soft {
645 Self::Soft(alternatives)
646 } else {
647 Self::Hard(alternatives)
648 }
649 })
650 }
651
652 /// Creates a new instance with a single hard requirement.
653 pub fn new(requirement: LexRequirement) -> Self {
654 Self::Hard(vec![requirement])
655 }
656
657 /// Creates a new instance with a single soft requirement.
658 pub fn new_soft(requirement: LexRequirement) -> Self {
659 Self::Soft(vec![requirement])
660 }
661
662 /// Adds an alternative requirement to the list of alternatives.
663 pub fn add_alternative(&mut self, requirement: LexRequirement) {
664 match self {
665 Self::Hard(alts) | Self::Soft(alts) => alts.push(requirement),
666 }
667 }
668
669 /// Returns the first (i.e. most preferred) `LexRequirement` among
670 /// alternative requirements.
671 pub fn into_single(self) -> LexRequirement {
672 match self {
673 Self::Hard(mut alts) | Self::Soft(mut alts) => alts.swap_remove(0),
674 }
675 }
676
677 /// Returns a reference to the first (i.e. most preferred) `LexRequirement`
678 /// among alternative requirements.
679 pub fn first(&self) -> &LexRequirement {
680 match self {
681 Self::Hard(alts) | Self::Soft(alts) => &alts[0],
682 }
683 }
684
685 /// Returns all alternatives as a vector of `LexRequirement` objects and a
686 /// boolean value indicating softness/hardness of the requirements.
687 pub fn into_alternatives(self) -> (Vec<LexRequirement>, bool) {
688 match self {
689 Self::Hard(alts) => (alts, false),
690 Self::Soft(alts) => (alts, true),
691 }
692 }
693}
694
695impl From<LexRequirement> for OrderingRequirements {
696 fn from(requirement: LexRequirement) -> Self {
697 Self::new(requirement)
698 }
699}
700
701impl From<LexOrdering> for OrderingRequirements {
702 fn from(ordering: LexOrdering) -> Self {
703 Self::new(ordering.into())
704 }
705}
706
707impl Deref for OrderingRequirements {
708 type Target = [LexRequirement];
709
710 fn deref(&self) -> &Self::Target {
711 match &self {
712 Self::Hard(alts) | Self::Soft(alts) => alts.as_slice(),
713 }
714 }
715}
716
717impl DerefMut for OrderingRequirements {
718 fn deref_mut(&mut self) -> &mut Self::Target {
719 match self {
720 Self::Hard(alts) | Self::Soft(alts) => alts.as_mut_slice(),
721 }
722 }
723}