1use nu_engine::ClosureEval;
2use nu_protocol::shell_error::generic::GenericError;
3use nu_protocol::{PipelineData, Record, ShellError, Span, Value, ast::CellPath};
4use nu_utils::IgnoreCaseExt;
5use std::cmp::Ordering;
6
7pub enum Comparator {
12 KeyClosure(ClosureEval),
13 CustomClosure(ClosureEval),
14 CellPath(CellPath),
15}
16
17pub fn sort(vec: &mut [Value], insensitive: bool, natural: bool) -> Result<(), ShellError> {
29 let mut compare_err: Option<ShellError> = None;
33
34 vec.sort_by(|a, b| {
35 if compare_err.is_some() {
37 return Ordering::Equal;
38 }
39
40 compare_values(a, b, insensitive, natural).unwrap_or_else(|err| {
41 compare_err.get_or_insert(err);
42 Ordering::Equal
43 })
44 });
45
46 if let Some(err) = compare_err {
47 Err(err)
48 } else {
49 Ok(())
50 }
51}
52
53pub fn sort_by(
55 vec: &mut [Value],
56 mut comparators: Vec<Comparator>,
57 head_span: Span,
58 insensitive: bool,
59 natural: bool,
60) -> Result<(), ShellError> {
61 if comparators.is_empty() {
62 return Err(ShellError::Generic(GenericError::new(
63 "expected name",
64 "requires a cell path or closure to sort data",
65 head_span,
66 )));
67 }
68
69 let mut compare_err: Option<ShellError> = None;
73
74 vec.sort_by(|a, b| {
75 compare_by(
76 a,
77 b,
78 &mut comparators,
79 head_span,
80 insensitive,
81 natural,
82 &mut compare_err,
83 )
84 });
85
86 if let Some(err) = compare_err {
87 Err(err)
88 } else {
89 Ok(())
90 }
91}
92
93pub fn sort_record(
97 record: Record,
98 sort_by_value: bool,
99 reverse: bool,
100 insensitive: bool,
101 natural: bool,
102) -> Result<Record, ShellError> {
103 let mut input_pairs: Vec<(String, Value)> = record.into_iter().collect();
104
105 let mut compare_err: Option<ShellError> = None;
109
110 if sort_by_value {
111 input_pairs.sort_by(|a, b| {
112 if compare_err.is_some() {
114 return Ordering::Equal;
115 }
116
117 compare_values(&a.1, &b.1, insensitive, natural).unwrap_or_else(|err| {
118 compare_err.get_or_insert(err);
119 Ordering::Equal
120 })
121 });
122 } else {
123 input_pairs.sort_by(|a, b| compare_strings(&a.0, &b.0, insensitive, natural));
124 };
125
126 if let Some(err) = compare_err {
127 return Err(err);
128 }
129
130 if reverse {
131 input_pairs.reverse()
132 }
133
134 Ok(input_pairs.into_iter().collect())
135}
136
137pub fn compare_by(
138 left: &Value,
139 right: &Value,
140 comparators: &mut [Comparator],
141 span: Span,
142 insensitive: bool,
143 natural: bool,
144 error: &mut Option<ShellError>,
145) -> Ordering {
146 if error.is_some() {
148 return Ordering::Equal;
149 }
150 for cmp in comparators.iter_mut() {
151 let result = match cmp {
152 Comparator::CellPath(cell_path) => {
153 compare_cell_path(left, right, cell_path, insensitive, natural)
154 }
155 Comparator::KeyClosure(closure) => {
156 compare_key_closure(left, right, closure, span, insensitive, natural)
157 }
158 Comparator::CustomClosure(closure) => {
159 compare_custom_closure(left, right, closure, span)
160 }
161 };
162 match result {
163 Ok(Ordering::Equal) => {}
164 Ok(ordering) => return ordering,
165 Err(err) => {
166 error.get_or_insert(err);
169 return Ordering::Equal;
170 }
171 }
172 }
173 Ordering::Equal
174}
175
176fn should_sort_as_string(val: &Value, natural: bool) -> bool {
181 matches!(
182 (val, natural),
183 (&Value::String { .. }, _)
184 | (&Value::Glob { .. }, _)
185 | (&Value::Int { .. }, true)
186 | (&Value::Float { .. }, true)
187 )
188}
189
190fn should_string_compare(left: &Value, right: &Value, natural: bool) -> bool {
193 should_sort_as_string(left, natural) && should_sort_as_string(right, natural)
194}
195
196pub fn compare_values(
197 left: &Value,
198 right: &Value,
199 insensitive: bool,
200 natural: bool,
201) -> Result<Ordering, ShellError> {
202 if should_string_compare(left, right, natural) {
203 Ok(compare_strings(
204 &left.coerce_str()?,
205 &right.coerce_str()?,
206 insensitive,
207 natural,
208 ))
209 } else {
210 match (left, right) {
211 (Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
212 Ok(lhs.total_cmp(rhs))
213 }
214 (Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
215 Ok((*lhs as f64).total_cmp(rhs))
216 }
217 (Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
218 Ok(lhs.total_cmp(&(*rhs as f64)))
219 }
220 _ => Ok(left.partial_cmp(right).unwrap_or(Ordering::Equal)),
221 }
222 }
223}
224
225pub fn compare_strings(left: &str, right: &str, insensitive: bool, natural: bool) -> Ordering {
226 fn compare_inner<T>(left: T, right: T, natural: bool) -> Ordering
227 where
228 T: AsRef<str> + Ord,
229 {
230 if natural {
231 alphanumeric_sort::compare_str(left, right)
232 } else {
233 left.cmp(&right)
234 }
235 }
236
237 if insensitive {
239 compare_inner(left.to_folded_case(), right.to_folded_case(), natural)
240 } else {
241 compare_inner(left, right, natural)
242 }
243}
244
245pub fn compare_cell_path(
246 left: &Value,
247 right: &Value,
248 cell_path: &CellPath,
249 insensitive: bool,
250 natural: bool,
251) -> Result<Ordering, ShellError> {
252 let left = left.follow_cell_path(&cell_path.members)?;
253 let right = right.follow_cell_path(&cell_path.members)?;
254 compare_values(&left, &right, insensitive, natural)
255}
256
257pub fn compare_key_closure(
258 left: &Value,
259 right: &Value,
260 closure_eval: &mut ClosureEval,
261 span: Span,
262 insensitive: bool,
263 natural: bool,
264) -> Result<Ordering, ShellError> {
265 let left_key = closure_eval
266 .run_with_value(left.clone())?
267 .into_value(span)?;
268 let right_key = closure_eval
269 .run_with_value(right.clone())?
270 .into_value(span)?;
271 compare_values(&left_key, &right_key, insensitive, natural)
272}
273
274pub fn compare_custom_closure(
275 left: &Value,
276 right: &Value,
277 closure_eval: &mut ClosureEval,
278 span: Span,
279) -> Result<Ordering, ShellError> {
280 closure_eval
281 .add_arg(left.clone())
282 .add_arg(right.clone())
283 .run_with_input(PipelineData::value(
284 Value::list(vec![left.clone(), right.clone()], span),
285 None,
286 ))
287 .and_then(|data| data.into_value(span))
288 .map(|val| {
289 if val.is_true() {
290 Ordering::Less
291 } else {
292 Ordering::Greater
293 }
294 })
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300 use nu_protocol::{ast::PathMember, casing::Casing, record};
301
302 #[test]
303 fn test_sort_floats_strict() {
304 let a = Value::test_float(7.0);
306 let b = Value::test_float(7.0 + 0.6 * f64::EPSILON * 7.0);
307 let c = Value::test_float(7.0 + 1.2 * f64::EPSILON * 7.0);
308
309 let mut list = vec![c.clone(), b.clone(), a.clone()];
316
317 assert!(sort(&mut list, false, false).is_ok());
319
320 assert_eq!(list, vec![a, b, c]);
321 }
322
323 #[test]
324 fn test_sort_basic() {
325 let mut list = vec![
326 Value::test_string("foo"),
327 Value::test_int(2),
328 Value::test_int(3),
329 Value::test_string("bar"),
330 Value::test_int(1),
331 Value::test_string("baz"),
332 ];
333
334 assert!(sort(&mut list, false, false).is_ok());
335 assert_eq!(
336 list,
337 vec![
338 Value::test_int(1),
339 Value::test_int(2),
340 Value::test_int(3),
341 Value::test_string("bar"),
342 Value::test_string("baz"),
343 Value::test_string("foo")
344 ]
345 );
346 }
347
348 #[test]
349 fn test_sort_nothing() {
350 let mut list = vec![
352 Value::test_int(1),
353 Value::test_nothing(),
354 Value::test_int(2),
355 Value::test_string("foo"),
356 Value::test_nothing(),
357 Value::test_string("bar"),
358 ];
359
360 assert!(sort(&mut list, false, false).is_ok());
361 assert_eq!(
362 list,
363 vec![
364 Value::test_int(1),
365 Value::test_int(2),
366 Value::test_string("bar"),
367 Value::test_string("foo"),
368 Value::test_nothing(),
369 Value::test_nothing()
370 ]
371 );
372
373 let mut values: Vec<Value> =
379 itertools::intersperse(Value::test_values(), Value::test_nothing()).collect();
380
381 let nulls = values
382 .iter()
383 .filter(|item| item == &&Value::test_nothing())
384 .count();
385
386 assert!(sort(&mut values, false, false).is_ok());
387
388 assert_eq!(&values[(nulls - 1)..], vec![Value::test_nothing(); nulls])
390 }
391
392 #[test]
393 fn test_sort_natural_basic() {
394 let mut list = vec![
395 Value::test_string("foo99"),
396 Value::test_string("foo9"),
397 Value::test_string("foo1"),
398 Value::test_string("foo100"),
399 Value::test_string("foo10"),
400 Value::test_string("1"),
401 Value::test_string("10"),
402 Value::test_string("100"),
403 Value::test_string("9"),
404 Value::test_string("99"),
405 ];
406
407 assert!(sort(&mut list, false, false).is_ok());
408 assert_eq!(
409 list,
410 vec![
411 Value::test_string("1"),
412 Value::test_string("10"),
413 Value::test_string("100"),
414 Value::test_string("9"),
415 Value::test_string("99"),
416 Value::test_string("foo1"),
417 Value::test_string("foo10"),
418 Value::test_string("foo100"),
419 Value::test_string("foo9"),
420 Value::test_string("foo99"),
421 ]
422 );
423
424 assert!(sort(&mut list, false, true).is_ok());
425 assert_eq!(
426 list,
427 vec![
428 Value::test_string("1"),
429 Value::test_string("9"),
430 Value::test_string("10"),
431 Value::test_string("99"),
432 Value::test_string("100"),
433 Value::test_string("foo1"),
434 Value::test_string("foo9"),
435 Value::test_string("foo10"),
436 Value::test_string("foo99"),
437 Value::test_string("foo100"),
438 ]
439 );
440 }
441
442 #[test]
443 fn test_sort_natural_mixed_types() {
444 let mut list = vec![
445 Value::test_string("1"),
446 Value::test_int(99),
447 Value::test_int(1),
448 Value::test_float(1000.0),
449 Value::test_int(9),
450 Value::test_string("9"),
451 Value::test_int(100),
452 Value::test_string("99"),
453 Value::test_float(2.0),
454 Value::test_string("100"),
455 Value::test_int(10),
456 Value::test_string("10"),
457 ];
458
459 assert!(sort(&mut list, false, false).is_ok());
460 assert_eq!(
461 list,
462 vec![
463 Value::test_int(1),
464 Value::test_float(2.0),
465 Value::test_int(9),
466 Value::test_int(10),
467 Value::test_int(99),
468 Value::test_int(100),
469 Value::test_float(1000.0),
470 Value::test_string("1"),
471 Value::test_string("10"),
472 Value::test_string("100"),
473 Value::test_string("9"),
474 Value::test_string("99")
475 ]
476 );
477
478 assert!(sort(&mut list, false, true).is_ok());
479 assert_eq!(
480 list,
481 vec![
482 Value::test_int(1),
483 Value::test_string("1"),
484 Value::test_float(2.0),
485 Value::test_int(9),
486 Value::test_string("9"),
487 Value::test_int(10),
488 Value::test_string("10"),
489 Value::test_int(99),
490 Value::test_string("99"),
491 Value::test_int(100),
492 Value::test_string("100"),
493 Value::test_float(1000.0),
494 ]
495 );
496 }
497
498 #[test]
499 fn test_sort_natural_no_numeric_values() {
500 let mut normal = vec![
503 Value::test_string("golf"),
504 Value::test_bool(false),
505 Value::test_string("alfa"),
506 Value::test_string("echo"),
507 Value::test_int(7),
508 Value::test_int(10),
509 Value::test_bool(true),
510 Value::test_string("uniform"),
511 Value::test_int(3),
512 Value::test_string("tango"),
513 ];
514 let mut natural = normal.clone();
515
516 assert!(sort(&mut normal, false, false).is_ok());
517 assert!(sort(&mut natural, false, true).is_ok());
518 assert_eq!(normal, natural);
519 }
520
521 #[test]
522 fn test_sort_natural_type_order() {
523 let mut list = vec![
544 Value::test_string("golf"),
545 Value::test_int(1),
546 Value::test_bool(false),
547 Value::test_string("alfa"),
548 Value::test_int(7),
549 Value::test_int(10),
550 Value::test_bool(true),
551 Value::test_string("uniform"),
552 Value::test_bool(true),
553 Value::test_int(3),
554 Value::test_bool(false),
555 Value::test_string("tango"),
556 ];
557
558 assert!(sort(&mut list, false, true).is_ok());
559 assert_eq!(
560 list,
561 vec![
562 Value::test_bool(false),
563 Value::test_bool(false),
564 Value::test_bool(true),
565 Value::test_bool(true),
566 Value::test_int(1),
567 Value::test_int(3),
568 Value::test_int(7),
569 Value::test_int(10),
570 Value::test_string("alfa"),
571 Value::test_string("golf"),
572 Value::test_string("tango"),
573 Value::test_string("uniform")
574 ]
575 );
576
577 let year_three = chrono::NaiveDate::from_ymd_opt(3, 1, 1)
583 .unwrap()
584 .and_hms_opt(0, 0, 0)
585 .unwrap()
586 .and_utc();
587
588 let mut list = vec![
589 Value::test_int(10),
590 Value::test_float(6.0),
591 Value::test_int(1),
592 Value::test_binary([3]),
593 Value::test_string("2"),
594 Value::test_date(year_three.into()),
595 Value::test_int(4),
596 Value::test_binary([52]),
597 Value::test_float(9.0),
598 Value::test_string("5"),
599 Value::test_date(chrono::DateTime::UNIX_EPOCH.into()),
600 Value::test_int(7),
601 Value::test_string("8"),
602 Value::test_float(3.0),
603 Value::test_string("foobar"),
604 ];
605 assert!(sort(&mut list, false, true).is_ok());
606 assert_eq!(
607 list,
608 vec![
609 Value::test_int(1),
610 Value::test_string("2"),
611 Value::test_float(3.0),
612 Value::test_int(4),
613 Value::test_string("5"),
614 Value::test_float(6.0),
615 Value::test_int(7),
616 Value::test_string("8"),
617 Value::test_float(9.0),
618 Value::test_int(10),
619 Value::test_string("foobar"),
620 Value::test_date(year_three.into()),
623 Value::test_date(chrono::DateTime::UNIX_EPOCH.into()),
624 Value::test_binary([3]),
625 Value::test_binary([52]),
626 ]
627 );
628 }
629
630 #[test]
631 fn test_sort_insensitive() {
632 let source = vec![
636 Value::test_string("FOO"),
637 Value::test_string("foo"),
638 Value::test_int(100),
639 Value::test_string("9"),
640 Value::test_string("bar"),
641 Value::test_int(10),
642 Value::test_string("baz"),
643 Value::test_string("BAR"),
644 ];
645 let mut list;
646
647 list = source.clone();
649 assert!(sort(&mut list, false, false).is_ok());
650 assert_eq!(
651 list,
652 vec![
653 Value::test_int(10),
654 Value::test_int(100),
655 Value::test_string("9"),
656 Value::test_string("BAR"),
657 Value::test_string("FOO"),
658 Value::test_string("bar"),
659 Value::test_string("baz"),
660 Value::test_string("foo"),
661 ]
662 );
663
664 list = source.clone();
666 assert!(sort(&mut list, false, true).is_ok());
667 assert_eq!(
668 list,
669 vec![
670 Value::test_string("9"),
671 Value::test_int(10),
672 Value::test_int(100),
673 Value::test_string("BAR"),
674 Value::test_string("FOO"),
675 Value::test_string("bar"),
676 Value::test_string("baz"),
677 Value::test_string("foo"),
678 ]
679 );
680
681 list = source.clone();
683 assert!(sort(&mut list, true, false).is_ok());
684 assert_eq!(
685 list,
686 vec![
687 Value::test_int(10),
688 Value::test_int(100),
689 Value::test_string("9"),
690 Value::test_string("bar"),
691 Value::test_string("BAR"),
692 Value::test_string("baz"),
693 Value::test_string("FOO"),
694 Value::test_string("foo"),
695 ]
696 );
697
698 list = source.clone();
700 assert!(sort(&mut list, true, true).is_ok());
701 assert_eq!(
702 list,
703 vec![
704 Value::test_string("9"),
705 Value::test_int(10),
706 Value::test_int(100),
707 Value::test_string("bar"),
708 Value::test_string("BAR"),
709 Value::test_string("baz"),
710 Value::test_string("FOO"),
711 Value::test_string("foo"),
712 ]
713 );
714 }
715
716 fn assert_record_eq(a: Record, b: Record) {
719 assert_eq!(
720 a.into_iter().collect::<Vec<_>>(),
721 b.into_iter().collect::<Vec<_>>(),
722 )
723 }
724
725 #[test]
726 fn test_sort_record_keys() {
727 let record = record! {
729 "golf" => Value::test_string("bar"),
730 "alfa" => Value::test_string("foo"),
731 "echo" => Value::test_int(123),
732 };
733
734 let sorted = sort_record(record, false, false, false, false).unwrap();
735 assert_record_eq(
736 sorted,
737 record! {
738 "alfa" => Value::test_string("foo"),
739 "echo" => Value::test_int(123),
740 "golf" => Value::test_string("bar"),
741 },
742 );
743 }
744
745 #[test]
746 fn test_sort_record_values() {
747 let record = record! {
765 "alfa" => Value::test_string("1"),
766 "bravo" => Value::test_int(99),
767 "charlie" => Value::test_int(1),
768 "delta" => Value::test_int(9),
769 "echo" => Value::test_string("9"),
770 "foxtrot" => Value::test_int(100),
771 "golf" => Value::test_string("99"),
772 "hotel" => Value::test_string("100"),
773 "india" => Value::test_int(10),
774 "juliett" => Value::test_string("10"),
775 };
776
777 let sorted = sort_record(record.clone(), true, false, false, false).unwrap();
779 assert_record_eq(
780 sorted,
781 record! {
782 "charlie" => Value::test_int(1),
783 "delta" => Value::test_int(9),
784 "india" => Value::test_int(10),
785 "bravo" => Value::test_int(99),
786 "foxtrot" => Value::test_int(100),
787 "alfa" => Value::test_string("1"),
788 "juliett" => Value::test_string("10"),
789 "hotel" => Value::test_string("100"),
790 "echo" => Value::test_string("9"),
791 "golf" => Value::test_string("99"),
792 },
793 );
794
795 let sorted = sort_record(record.clone(), true, false, false, true).unwrap();
797 assert_record_eq(
798 sorted,
799 record! {
800 "alfa" => Value::test_string("1"),
801 "charlie" => Value::test_int(1),
802 "delta" => Value::test_int(9),
803 "echo" => Value::test_string("9"),
804 "india" => Value::test_int(10),
805 "juliett" => Value::test_string("10"),
806 "bravo" => Value::test_int(99),
807 "golf" => Value::test_string("99"),
808 "foxtrot" => Value::test_int(100),
809 "hotel" => Value::test_string("100"),
810 },
811 );
812 }
813
814 #[test]
815 fn test_sort_equivalent() {
816 let phonetic = vec![
818 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india",
819 "juliett", "kilo", "lima", "mike", "november", "oscar", "papa", "quebec", "romeo",
820 "sierra", "tango", "uniform", "victor", "whiskey", "xray", "yankee", "zulu",
821 ];
822
823 let mut values: Vec<Value> = Value::test_values()
825 .into_iter()
826 .filter(|val| !matches!(val, Value::Error { .. }))
827 .collect();
828
829 values.sort_by(|a, b| b.partial_cmp(a).unwrap());
831
832 let mut list = values.clone();
833 let mut table: Vec<Value> = values
834 .clone()
835 .into_iter()
836 .map(|val| Value::test_record(record! { "value" => val }))
837 .collect();
838 let record = Record::from_iter(phonetic.into_iter().map(str::to_string).zip(values));
839
840 let comparator = Comparator::CellPath(CellPath {
841 members: vec![PathMember::String {
842 val: "value".to_string(),
843 span: Span::test_data(),
844 optional: false,
845 casing: Casing::Sensitive,
846 }],
847 });
848
849 assert!(sort(&mut list, false, false).is_ok());
850 assert!(
851 sort_by(
852 &mut table,
853 vec![comparator],
854 Span::test_data(),
855 false,
856 false
857 )
858 .is_ok()
859 );
860
861 let record_sorted = sort_record(record.clone(), true, false, false, false).unwrap();
862 let record_vals: Vec<Value> = record_sorted.into_iter().map(|pair| pair.1).collect();
863
864 let table_vals: Vec<Value> = table
865 .clone()
866 .into_iter()
867 .map(|record| record.into_record().unwrap().remove("value").unwrap())
868 .collect();
869
870 assert_eq!(list, record_vals);
871 assert_eq!(record_vals, table_vals);
872 }
874}