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}