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)]
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 exprs = exprs.into_iter();
371        let mut candidate = Self {
372            // not valid yet; valid publicly-returned instance must be non-empty
373            exprs: Vec::new(),
374            set: HashSet::new(),
375        };
376        for expr in exprs {
377            candidate.push(expr);
378        }
379        if candidate.exprs.is_empty() {
380            None
381        } else {
382            Some(candidate)
383        }
384    }
385
386    /// Appends an element to the back of the `LexOrdering`.
387    pub fn push(&mut self, sort_expr: PhysicalSortExpr) {
388        if self.set.insert(Arc::clone(&sort_expr.expr)) {
389            self.exprs.push(sort_expr);
390        }
391    }
392
393    /// Add all elements from `iter` to the `LexOrdering`.
394    pub fn extend(&mut self, sort_exprs: impl IntoIterator<Item = PhysicalSortExpr>) {
395        for sort_expr in sort_exprs {
396            self.push(sort_expr);
397        }
398    }
399
400    /// Returns the leading `PhysicalSortExpr` of the `LexOrdering`. Note that
401    /// this function does not return an `Option`, as a `LexOrdering` is always
402    /// non-degenerate (i.e. it contains at least one element).
403    pub fn first(&self) -> &PhysicalSortExpr {
404        // Can safely `unwrap` because `LexOrdering` is non-degenerate:
405        self.exprs.first().unwrap()
406    }
407
408    /// Returns the number of elements that can be stored in the `LexOrdering`
409    /// without reallocating.
410    pub fn capacity(&self) -> usize {
411        self.exprs.capacity()
412    }
413
414    /// Truncates the `LexOrdering`, keeping only the first `len` elements.
415    /// Returns `true` if truncation made a change, `false` otherwise. Negative
416    /// cases happen in two scenarios: (1) When `len` is greater than or equal
417    /// to the number of expressions inside this `LexOrdering`, making truncation
418    /// a no-op, or (2) when `len` is `0`, making truncation impossible.
419    pub fn truncate(&mut self, len: usize) -> bool {
420        if len == 0 || len >= self.exprs.len() {
421            return false;
422        }
423        for PhysicalSortExpr { expr, .. } in self.exprs[len..].iter() {
424            self.set.remove(expr);
425        }
426        self.exprs.truncate(len);
427        true
428    }
429}
430
431impl PartialEq for LexOrdering {
432    fn eq(&self, other: &Self) -> bool {
433        let Self {
434            exprs,
435            set: _, // derived from `exprs`
436        } = self;
437        // PartialEq must be consistent with PartialOrd
438        exprs == &other.exprs
439    }
440}
441impl Eq for LexOrdering {}
442impl PartialOrd for LexOrdering {
443    /// There is a partial ordering among `LexOrdering` objects. For example, the
444    /// ordering `[a ASC]` is coarser (less) than ordering `[a ASC, b ASC]`.
445    /// If two orderings do not share a prefix, they are incomparable.
446    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
447        // PartialEq must be consistent with PartialOrd
448        self.exprs
449            .iter()
450            .zip(other.exprs.iter())
451            .all(|(lhs, rhs)| lhs == rhs)
452            .then(|| self.len().cmp(&other.len()))
453    }
454}
455
456impl<const N: usize> From<[PhysicalSortExpr; N]> for LexOrdering {
457    fn from(value: [PhysicalSortExpr; N]) -> Self {
458        // TODO: Replace this assertion with a condition on the generic parameter
459        //       when Rust supports it.
460        assert!(N > 0);
461        Self::new(value)
462            .expect("A LexOrdering from non-empty array must be non-degenerate")
463    }
464}
465
466impl Deref for LexOrdering {
467    type Target = [PhysicalSortExpr];
468
469    fn deref(&self) -> &Self::Target {
470        self.exprs.as_slice()
471    }
472}
473
474impl Display for LexOrdering {
475    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
476        let mut first = true;
477        for sort_expr in &self.exprs {
478            if first {
479                first = false;
480            } else {
481                write!(f, ", ")?;
482            }
483            write!(f, "{sort_expr}")?;
484        }
485        Ok(())
486    }
487}
488
489impl IntoIterator for LexOrdering {
490    type Item = PhysicalSortExpr;
491    type IntoIter = IntoIter<Self::Item>;
492
493    fn into_iter(self) -> Self::IntoIter {
494        self.exprs.into_iter()
495    }
496}
497
498impl<'a> IntoIterator for &'a LexOrdering {
499    type Item = &'a PhysicalSortExpr;
500    type IntoIter = std::slice::Iter<'a, PhysicalSortExpr>;
501
502    fn into_iter(self) -> Self::IntoIter {
503        self.exprs.iter()
504    }
505}
506
507impl From<LexOrdering> for Vec<PhysicalSortExpr> {
508    fn from(ordering: LexOrdering) -> Self {
509        ordering.exprs
510    }
511}
512
513/// This object represents a lexicographical ordering requirement and contains
514/// a vector of `PhysicalSortRequirement` objects.
515///
516/// For example, a `vec![a Some(ASC), b None]` represents a lexicographical
517/// requirement that firsts imposes an ordering by column `a` in ascending
518/// order, then by column `b` in *any* (ascending or descending) order. The
519/// ordering is non-degenerate, meaning it contains at least one element, and
520/// it is duplicate-free, meaning it does not contain multiple entries for the
521/// same column.
522///
523/// Note that a `LexRequirement` need not enforce the uniqueness of its sort
524/// expressions after construction like a `LexOrdering` does, because it provides
525/// no mutation methods. If such methods become necessary, we will need to
526/// enforce uniqueness like the latter object.
527#[derive(Debug, Clone, PartialEq)]
528pub struct LexRequirement {
529    reqs: Vec<PhysicalSortRequirement>,
530}
531
532impl LexRequirement {
533    /// Creates a new [`LexRequirement`] from the given vector of sort expressions.
534    /// If the vector is empty, returns `None`.
535    pub fn new(reqs: impl IntoIterator<Item = PhysicalSortRequirement>) -> Option<Self> {
536        let (non_empty, requirements) = Self::construct(reqs);
537        non_empty.then_some(requirements)
538    }
539
540    /// Returns the leading `PhysicalSortRequirement` of the `LexRequirement`.
541    /// Note that this function does not return an `Option`, as a `LexRequirement`
542    /// is always non-degenerate (i.e. it contains at least one element).
543    pub fn first(&self) -> &PhysicalSortRequirement {
544        // Can safely `unwrap` because `LexRequirement` is non-degenerate:
545        self.reqs.first().unwrap()
546    }
547
548    /// Constructs a new `LexRequirement` from the given sort requirements w/o
549    /// enforcing non-degeneracy. This function is used internally and is not
550    /// meant (or safe) for external use.
551    fn construct(
552        reqs: impl IntoIterator<Item = PhysicalSortRequirement>,
553    ) -> (bool, Self) {
554        let mut set = HashSet::new();
555        let reqs = reqs
556            .into_iter()
557            .filter_map(|r| set.insert(Arc::clone(&r.expr)).then_some(r))
558            .collect();
559        (!set.is_empty(), Self { reqs })
560    }
561}
562
563impl<const N: usize> From<[PhysicalSortRequirement; N]> for LexRequirement {
564    fn from(value: [PhysicalSortRequirement; N]) -> Self {
565        // TODO: Replace this assertion with a condition on the generic parameter
566        //       when Rust supports it.
567        assert!(N > 0);
568        let (non_empty, requirement) = Self::construct(value);
569        debug_assert!(non_empty);
570        requirement
571    }
572}
573
574impl Deref for LexRequirement {
575    type Target = [PhysicalSortRequirement];
576
577    fn deref(&self) -> &Self::Target {
578        self.reqs.as_slice()
579    }
580}
581
582impl IntoIterator for LexRequirement {
583    type Item = PhysicalSortRequirement;
584    type IntoIter = IntoIter<Self::Item>;
585
586    fn into_iter(self) -> Self::IntoIter {
587        self.reqs.into_iter()
588    }
589}
590
591impl<'a> IntoIterator for &'a LexRequirement {
592    type Item = &'a PhysicalSortRequirement;
593    type IntoIter = std::slice::Iter<'a, PhysicalSortRequirement>;
594
595    fn into_iter(self) -> Self::IntoIter {
596        self.reqs.iter()
597    }
598}
599
600impl From<LexRequirement> for Vec<PhysicalSortRequirement> {
601    fn from(requirement: LexRequirement) -> Self {
602        requirement.reqs
603    }
604}
605
606// Cross-conversion utilities between `LexOrdering` and `LexRequirement`
607impl From<LexOrdering> for LexRequirement {
608    fn from(value: LexOrdering) -> Self {
609        // Can construct directly as `value` is non-degenerate:
610        let (non_empty, requirements) =
611            Self::construct(value.into_iter().map(Into::into));
612        debug_assert!(non_empty);
613        requirements
614    }
615}
616
617impl From<LexRequirement> for LexOrdering {
618    fn from(value: LexRequirement) -> Self {
619        // Can construct directly as `value` is non-degenerate
620        Self::new(value.into_iter().map(Into::into))
621            .expect("A LexOrdering from LexRequirement must be non-degenerate")
622    }
623}
624
625/// Represents a plan's input ordering requirements. Vector elements represent
626/// alternative ordering requirements in the order of preference. The list of
627/// alternatives can be either hard or soft, depending on whether the operator
628/// can work without an input ordering.
629///
630/// # Invariants
631///
632/// The following always hold true for a `OrderingRequirements`:
633///
634/// 1. It is non-degenerate, meaning it contains at least one ordering. The
635///    absence of an input ordering requirement is represented by a `None` value
636///    in `ExecutionPlan` APIs, which return an `Option<OrderingRequirements>`.
637#[derive(Debug, Clone, PartialEq)]
638pub enum OrderingRequirements {
639    /// The operator is not able to work without one of these requirements.
640    Hard(Vec<LexRequirement>),
641    /// The operator can benefit from these input orderings when available,
642    /// but can still work in the absence of any input ordering.
643    Soft(Vec<LexRequirement>),
644}
645
646impl OrderingRequirements {
647    /// Creates a new instance from the given alternatives. If an empty list of
648    /// alternatives are given, returns `None`.
649    pub fn new_alternatives(
650        alternatives: impl IntoIterator<Item = LexRequirement>,
651        soft: bool,
652    ) -> Option<Self> {
653        let alternatives = alternatives.into_iter().collect::<Vec<_>>();
654        (!alternatives.is_empty()).then(|| {
655            if soft {
656                Self::Soft(alternatives)
657            } else {
658                Self::Hard(alternatives)
659            }
660        })
661    }
662
663    /// Creates a new instance with a single hard requirement.
664    pub fn new(requirement: LexRequirement) -> Self {
665        Self::Hard(vec![requirement])
666    }
667
668    /// Creates a new instance with a single soft requirement.
669    pub fn new_soft(requirement: LexRequirement) -> Self {
670        Self::Soft(vec![requirement])
671    }
672
673    /// Adds an alternative requirement to the list of alternatives.
674    pub fn add_alternative(&mut self, requirement: LexRequirement) {
675        match self {
676            Self::Hard(alts) | Self::Soft(alts) => alts.push(requirement),
677        }
678    }
679
680    /// Returns the first (i.e. most preferred) `LexRequirement` among
681    /// alternative requirements.
682    pub fn into_single(self) -> LexRequirement {
683        match self {
684            Self::Hard(mut alts) | Self::Soft(mut alts) => alts.swap_remove(0),
685        }
686    }
687
688    /// Returns a reference to the first (i.e. most preferred) `LexRequirement`
689    /// among alternative requirements.
690    pub fn first(&self) -> &LexRequirement {
691        match self {
692            Self::Hard(alts) | Self::Soft(alts) => &alts[0],
693        }
694    }
695
696    /// Returns all alternatives as a vector of `LexRequirement` objects and a
697    /// boolean value indicating softness/hardness of the requirements.
698    pub fn into_alternatives(self) -> (Vec<LexRequirement>, bool) {
699        match self {
700            Self::Hard(alts) => (alts, false),
701            Self::Soft(alts) => (alts, true),
702        }
703    }
704}
705
706impl From<LexRequirement> for OrderingRequirements {
707    fn from(requirement: LexRequirement) -> Self {
708        Self::new(requirement)
709    }
710}
711
712impl From<LexOrdering> for OrderingRequirements {
713    fn from(ordering: LexOrdering) -> Self {
714        Self::new(ordering.into())
715    }
716}
717
718impl Deref for OrderingRequirements {
719    type Target = [LexRequirement];
720
721    fn deref(&self) -> &Self::Target {
722        match &self {
723            Self::Hard(alts) | Self::Soft(alts) => alts.as_slice(),
724        }
725    }
726}
727
728impl DerefMut for OrderingRequirements {
729    fn deref_mut(&mut self) -> &mut Self::Target {
730        match self {
731            Self::Hard(alts) | Self::Soft(alts) => alts.as_mut_slice(),
732        }
733    }
734}