nu_data/
value.rs

1use crate::base::coerce_compare;
2use crate::base::shape::{Column, InlineShape};
3use crate::primitive::style_primitive;
4use bigdecimal::Signed;
5use chrono::{DateTime, NaiveDate, Utc};
6use nu_errors::ShellError;
7use nu_protocol::hir::Operator;
8use nu_protocol::ShellTypeName;
9use nu_protocol::{Primitive, Type, UntaggedValue};
10use nu_source::{DebugDocBuilder, PrettyDebug, Span, Tagged};
11use nu_table::TextStyle;
12use num_bigint::BigInt;
13use num_bigint::ToBigInt;
14use num_traits::{ToPrimitive, Zero};
15use std::collections::HashMap;
16
17pub struct Date;
18
19impl Date {
20    pub fn from_regular_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
21        let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| {
22            ShellError::labeled_error(
23                &format!("Date parse error: {}", err),
24                "original value",
25                s.tag,
26            )
27        })?;
28
29        let date = date.with_timezone(&chrono::offset::Utc);
30
31        Ok(UntaggedValue::Primitive(Primitive::Date(date.into())))
32    }
33
34    pub fn naive_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
35        let date = NaiveDate::parse_from_str(s.item, "%Y-%m-%d").map_err(|reason| {
36            ShellError::labeled_error(
37                &format!("Date parse error: {}", reason),
38                "original value",
39                s.tag,
40            )
41        })?;
42
43        Ok(UntaggedValue::Primitive(Primitive::Date(
44            DateTime::<Utc>::from_utc(date.and_hms(12, 34, 56), Utc).into(),
45        )))
46    }
47}
48
49pub fn date_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
50    Date::from_regular_str(s)
51}
52
53pub fn date_naive_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
54    Date::naive_from_str(s)
55}
56
57pub fn merge_values(
58    left: &UntaggedValue,
59    right: &UntaggedValue,
60) -> Result<UntaggedValue, (&'static str, &'static str)> {
61    match (left, right) {
62        (UntaggedValue::Row(columns), UntaggedValue::Row(columns_b)) => {
63            Ok(UntaggedValue::Row(columns.merge_from(columns_b)))
64        }
65        (left, right) => Err((left.type_name(), right.type_name())),
66    }
67}
68
69fn zero_division_error() -> UntaggedValue {
70    UntaggedValue::Error(ShellError::untagged_runtime_error("division by zero"))
71}
72
73pub fn unsafe_compute_values(
74    operator: Operator,
75    left: &UntaggedValue,
76    right: &UntaggedValue,
77) -> Result<UntaggedValue, (&'static str, &'static str)> {
78    let computed = compute_values(operator, left, right);
79
80    if computed.is_ok() {
81        return computed;
82    }
83
84    match (left, right) {
85        (UntaggedValue::Primitive(lhs), UntaggedValue::Primitive(rhs)) => match (lhs, rhs) {
86            (Primitive::Filesize(x), Primitive::Int(y)) => match operator {
87                Operator::Multiply => {
88                    Ok(UntaggedValue::Primitive(Primitive::Filesize(x * *y as u64)))
89                }
90                Operator::Divide => {
91                    Ok(UntaggedValue::Primitive(Primitive::Filesize(x / *y as u64)))
92                }
93                _ => Err((left.type_name(), right.type_name())),
94            },
95            (Primitive::Int(x), Primitive::Filesize(y)) => match operator {
96                Operator::Multiply => {
97                    Ok(UntaggedValue::Primitive(Primitive::Filesize(*x as u64 * y)))
98                }
99                _ => Err((left.type_name(), right.type_name())),
100            },
101            _ => Err((left.type_name(), right.type_name())),
102        },
103        _ => Err((left.type_name(), right.type_name())),
104    }
105}
106
107pub fn compute_values(
108    operator: Operator,
109    left: &UntaggedValue,
110    right: &UntaggedValue,
111) -> Result<UntaggedValue, (&'static str, &'static str)> {
112    match (left, right) {
113        (UntaggedValue::Primitive(lhs), UntaggedValue::Primitive(rhs)) => match (lhs, rhs) {
114            (Primitive::Filesize(x), Primitive::Filesize(y)) => {
115                let result = match operator {
116                    Operator::Plus => Ok(x + y),
117                    Operator::Minus => Ok(x - y),
118                    Operator::Multiply => Ok(x * y),
119                    Operator::Divide => {
120                        if y.is_zero() {
121                            Err((left.type_name(), right.type_name()))
122                        } else {
123                            Ok(x / y)
124                        }
125                    }
126                    _ => Err((left.type_name(), right.type_name())),
127                }?;
128                Ok(UntaggedValue::Primitive(Primitive::Filesize(result)))
129            }
130            (Primitive::Filesize(x), Primitive::Int(y)) => match operator {
131                // Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Filesize(x + *y as u64))),
132                // Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Filesize(x - *y as u64))),
133                Operator::Multiply => {
134                    Ok(UntaggedValue::Primitive(Primitive::Filesize(x * *y as u64)))
135                }
136                Operator::Divide => {
137                    Ok(UntaggedValue::Primitive(Primitive::Filesize(x / *y as u64)))
138                }
139                _ => Err((left.type_name(), right.type_name())),
140            },
141            (Primitive::Int(x), Primitive::Filesize(y)) => match operator {
142                // Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Filesize(*x as u64 + y))),
143                // Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Filesize(*x as u64 - y))),
144                Operator::Multiply => {
145                    Ok(UntaggedValue::Primitive(Primitive::Filesize(*x as u64 * y)))
146                }
147                // Operator::Divide => {
148                //     Ok(UntaggedValue::Primitive(Primitive::Filesize(*x as u64 / y)))
149                // }
150                _ => Err((left.type_name(), right.type_name())),
151            },
152            (Primitive::Int(x), Primitive::Int(y)) => match operator {
153                Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Int(x + y))),
154                Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))),
155                Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
156                Operator::Divide => {
157                    if y.is_zero() {
158                        Ok(zero_division_error())
159                    } else if x - (y * (x / y)) == 0 {
160                        Ok(UntaggedValue::Primitive(Primitive::Int(x / y)))
161                    } else {
162                        Ok(UntaggedValue::Primitive(Primitive::Decimal(
163                            bigdecimal::BigDecimal::from(*x) / bigdecimal::BigDecimal::from(*y),
164                        )))
165                    }
166                }
167                Operator::Modulo => {
168                    if y.is_zero() {
169                        Ok(zero_division_error())
170                    } else {
171                        Ok(UntaggedValue::Primitive(Primitive::Int(x % y)))
172                    }
173                }
174                Operator::Pow => {
175                    let prim_u32 = ToPrimitive::to_u32(y);
176
177                    let sign = match x.is_negative() {
178                        true => -1,
179                        false => 1,
180                    };
181
182                    if !y.is_negative() {
183                        match prim_u32 {
184                            Some(num) => Ok(UntaggedValue::Primitive(Primitive::Int(
185                                sign * (x.pow(num)),
186                            ))),
187                            _ => Err((left.type_name(), right.type_name())),
188                        }
189                    } else {
190                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
191                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
192
193                        let pow =
194                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
195
196                        match pow {
197                            Some(p) => Ok(UntaggedValue::Primitive(Primitive::Decimal(p))),
198                            _ => Err((left.type_name(), right.type_name())),
199                        }
200                    }
201                }
202                _ => Err((left.type_name(), right.type_name())),
203            },
204            (Primitive::Int(x), Primitive::BigInt(y)) => match operator {
205                Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::BigInt(
206                    BigInt::from(*x) + y,
207                ))),
208                Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::BigInt(
209                    BigInt::from(*x) - y,
210                ))),
211                Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::BigInt(
212                    BigInt::from(*x) * y,
213                ))),
214                Operator::Divide => {
215                    if y.is_zero() {
216                        Ok(zero_division_error())
217                    } else if x - (y * (x / y)) == BigInt::from(0) {
218                        Ok(UntaggedValue::Primitive(Primitive::BigInt(
219                            BigInt::from(*x) / y,
220                        )))
221                    } else {
222                        Ok(UntaggedValue::Primitive(Primitive::Decimal(
223                            bigdecimal::BigDecimal::from(*x)
224                                / bigdecimal::BigDecimal::from(y.clone()),
225                        )))
226                    }
227                }
228                Operator::Modulo => {
229                    if y.is_zero() {
230                        Ok(zero_division_error())
231                    } else {
232                        Ok(UntaggedValue::Primitive(Primitive::BigInt(x % y)))
233                    }
234                }
235                Operator::Pow => {
236                    let prim_u32 = ToPrimitive::to_u32(y);
237
238                    let sign = match x.is_negative() {
239                        true => -1,
240                        false => 1,
241                    };
242
243                    if !y.is_negative() {
244                        match prim_u32 {
245                            Some(num) => Ok(UntaggedValue::Primitive(Primitive::Int(
246                                sign * (x.pow(num)),
247                            ))),
248                            _ => Err((left.type_name(), right.type_name())),
249                        }
250                    } else {
251                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
252                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
253                        let pow =
254                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
255                        match pow {
256                            Some(p) => Ok(UntaggedValue::Primitive(Primitive::Decimal(p))),
257                            _ => Err((left.type_name(), right.type_name())),
258                        }
259                    }
260                }
261                _ => Err((left.type_name(), right.type_name())),
262            },
263            (Primitive::BigInt(x), Primitive::Int(y)) => match operator {
264                Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::BigInt(
265                    x + BigInt::from(*y),
266                ))),
267                Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::BigInt(
268                    x - BigInt::from(*y),
269                ))),
270                Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::BigInt(
271                    x * BigInt::from(*y),
272                ))),
273                Operator::Divide => {
274                    if y.is_zero() {
275                        Ok(zero_division_error())
276                    } else if x - (y * (x / y)) == BigInt::from(0) {
277                        Ok(UntaggedValue::Primitive(Primitive::BigInt(
278                            x / BigInt::from(*y),
279                        )))
280                    } else {
281                        Ok(UntaggedValue::Primitive(Primitive::Decimal(
282                            bigdecimal::BigDecimal::from(x.clone())
283                                / bigdecimal::BigDecimal::from(*y),
284                        )))
285                    }
286                }
287                Operator::Modulo => {
288                    if y.is_zero() {
289                        Ok(zero_division_error())
290                    } else {
291                        Ok(UntaggedValue::Primitive(Primitive::BigInt(x % y)))
292                    }
293                }
294                Operator::Pow => {
295                    let prim_u32 = ToPrimitive::to_u32(y);
296
297                    let sign = match x.is_negative() {
298                        true => -1,
299                        false => 1,
300                    };
301
302                    if !y.is_negative() {
303                        match prim_u32 {
304                            Some(num) => Ok(UntaggedValue::Primitive(Primitive::BigInt(
305                                (sign.to_bigint().unwrap_or_default()) * x.pow(num),
306                            ))),
307                            _ => Err((left.type_name(), right.type_name())),
308                        }
309                    } else {
310                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
311                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
312                        let pow = bigdecimal::FromPrimitive::from_f64((sign as f64) * xp.powf(yp));
313                        match pow {
314                            Some(p) => Ok(UntaggedValue::Primitive(Primitive::Decimal(p))),
315                            _ => Err((left.type_name(), right.type_name())),
316                        }
317                    }
318                }
319                _ => Err((left.type_name(), right.type_name())),
320            },
321            (Primitive::BigInt(x), Primitive::BigInt(y)) => match operator {
322                Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::BigInt(x + y))),
323                Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::BigInt(x - y))),
324                Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::BigInt(x * y))),
325                Operator::Divide => {
326                    if y.is_zero() {
327                        Ok(zero_division_error())
328                    } else if x - (y * (x / y)) == BigInt::from(0) {
329                        Ok(UntaggedValue::Primitive(Primitive::BigInt(x / y)))
330                    } else {
331                        Ok(UntaggedValue::Primitive(Primitive::Decimal(
332                            bigdecimal::BigDecimal::from(x.clone())
333                                / bigdecimal::BigDecimal::from(y.clone()),
334                        )))
335                    }
336                }
337                Operator::Modulo => {
338                    if y.is_zero() {
339                        Ok(zero_division_error())
340                    } else {
341                        Ok(UntaggedValue::Primitive(Primitive::BigInt(x % y)))
342                    }
343                }
344                Operator::Pow => {
345                    let prim_u32 = ToPrimitive::to_u32(y);
346
347                    let sign = match x.is_negative() {
348                        true => -1,
349                        false => 1,
350                    };
351
352                    if !y.is_negative() {
353                        match prim_u32 {
354                            Some(num) => Ok(UntaggedValue::Primitive(Primitive::BigInt(
355                                (sign.to_bigint().unwrap_or_default()).pow(num),
356                            ))),
357                            _ => Err((left.type_name(), right.type_name())),
358                        }
359                    } else {
360                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
361                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
362
363                        let pow =
364                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
365
366                        match pow {
367                            Some(p) => Ok(UntaggedValue::Primitive(Primitive::Decimal(p))),
368                            _ => Err((left.type_name(), right.type_name())),
369                        }
370                    }
371                }
372                _ => Err((left.type_name(), right.type_name())),
373            },
374            (Primitive::Decimal(x), Primitive::Int(y)) => {
375                let result = match operator {
376                    Operator::Plus => Ok(x + bigdecimal::BigDecimal::from(*y)),
377                    Operator::Minus => Ok(x - bigdecimal::BigDecimal::from(*y)),
378                    Operator::Multiply => Ok(x * bigdecimal::BigDecimal::from(*y)),
379                    Operator::Divide => {
380                        if y.is_zero() {
381                            return Ok(zero_division_error());
382                        }
383                        Ok(x / bigdecimal::BigDecimal::from(*y))
384                    }
385                    Operator::Modulo => {
386                        if y.is_zero() {
387                            return Ok(zero_division_error());
388                        }
389                        Ok(x % bigdecimal::BigDecimal::from(*y))
390                    }
391
392                    Operator::Pow => {
393                        let sign = match x.is_negative() {
394                            true => -1,
395                            false => 1,
396                        };
397
398                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
399                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
400                        let pow =
401                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
402                        match pow {
403                            Some(p) => Ok(p),
404                            None => Err((left.type_name(), right.type_name())),
405                        }
406                    }
407                    _ => Err((left.type_name(), right.type_name())),
408                }?;
409                Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
410            }
411            (Primitive::Int(x), Primitive::Decimal(y)) => {
412                let result = match operator {
413                    Operator::Plus => Ok(bigdecimal::BigDecimal::from(*x) + y),
414                    Operator::Minus => Ok(bigdecimal::BigDecimal::from(*x) - y),
415                    Operator::Multiply => Ok(bigdecimal::BigDecimal::from(*x) * y),
416                    Operator::Divide => {
417                        if y.is_zero() {
418                            return Ok(zero_division_error());
419                        }
420                        Ok(bigdecimal::BigDecimal::from(*x) / y)
421                    }
422                    Operator::Modulo => {
423                        if y.is_zero() {
424                            return Ok(zero_division_error());
425                        }
426                        Ok(bigdecimal::BigDecimal::from(*x) % y)
427                    }
428
429                    Operator::Pow => {
430                        let sign = match x.is_negative() {
431                            true => -1,
432                            false => 1,
433                        };
434
435                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
436                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
437                        let pow =
438                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
439                        match pow {
440                            Some(p) => Ok(p),
441                            None => Err((left.type_name(), right.type_name())),
442                        }
443                    }
444                    _ => Err((left.type_name(), right.type_name())),
445                }?;
446                Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
447            }
448            (Primitive::Decimal(x), Primitive::BigInt(y)) => {
449                let result = match operator {
450                    Operator::Plus => Ok(x + bigdecimal::BigDecimal::from(y.clone())),
451                    Operator::Minus => Ok(x - bigdecimal::BigDecimal::from(y.clone())),
452                    Operator::Multiply => Ok(x * bigdecimal::BigDecimal::from(y.clone())),
453                    Operator::Divide => {
454                        if y.is_zero() {
455                            return Ok(zero_division_error());
456                        }
457                        Ok(x / bigdecimal::BigDecimal::from(y.clone()))
458                    }
459                    Operator::Modulo => {
460                        if y.is_zero() {
461                            return Ok(zero_division_error());
462                        }
463                        Ok(x % bigdecimal::BigDecimal::from(y.clone()))
464                    }
465
466                    Operator::Pow => {
467                        let sign = match x.is_negative() {
468                            true => -1,
469                            false => 1,
470                        };
471
472                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
473                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
474                        let pow =
475                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
476                        match pow {
477                            Some(p) => Ok(p),
478                            None => Err((left.type_name(), right.type_name())),
479                        }
480                    }
481                    _ => Err((left.type_name(), right.type_name())),
482                }?;
483                Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
484            }
485            (Primitive::BigInt(x), Primitive::Decimal(y)) => {
486                let result = match operator {
487                    Operator::Plus => Ok(bigdecimal::BigDecimal::from(x.clone()) + y),
488                    Operator::Minus => Ok(bigdecimal::BigDecimal::from(x.clone()) - y),
489                    Operator::Multiply => Ok(bigdecimal::BigDecimal::from(x.clone()) * y),
490                    Operator::Divide => {
491                        if y.is_zero() {
492                            return Ok(zero_division_error());
493                        }
494                        Ok(bigdecimal::BigDecimal::from(x.clone()) / y)
495                    }
496                    Operator::Modulo => {
497                        if y.is_zero() {
498                            return Ok(zero_division_error());
499                        }
500                        Ok(bigdecimal::BigDecimal::from(x.clone()) % y)
501                    }
502
503                    Operator::Pow => {
504                        let sign = match x.is_negative() {
505                            true => -1,
506                            false => 1,
507                        };
508
509                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
510                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
511                        let pow =
512                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
513                        match pow {
514                            Some(p) => Ok(p),
515                            None => Err((left.type_name(), right.type_name())),
516                        }
517                    }
518                    _ => Err((left.type_name(), right.type_name())),
519                }?;
520                Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
521            }
522            (Primitive::Decimal(x), Primitive::Decimal(y)) => {
523                let result = match operator {
524                    Operator::Plus => Ok(x + y),
525                    Operator::Minus => Ok(x - y),
526                    Operator::Multiply => Ok(x * y),
527                    Operator::Divide => {
528                        if y.is_zero() {
529                            return Ok(zero_division_error());
530                        }
531                        Ok(x / y)
532                    }
533                    Operator::Modulo => {
534                        if y.is_zero() {
535                            return Ok(zero_division_error());
536                        }
537                        Ok(x % y)
538                    }
539
540                    Operator::Pow => {
541                        let sign = match x.is_negative() {
542                            true => -1,
543                            false => 1,
544                        };
545
546                        let yp = bigdecimal::ToPrimitive::to_f64(y).unwrap_or(0.0);
547                        let xp = bigdecimal::ToPrimitive::to_f64(x).unwrap_or(0.0);
548                        let pow =
549                            bigdecimal::FromPrimitive::from_f64((sign as f64) * (xp.powf(yp)));
550                        match pow {
551                            Some(p) => Ok(p),
552                            None => Err((left.type_name(), right.type_name())),
553                        }
554                    }
555                    _ => Err((left.type_name(), right.type_name())),
556                }?;
557                Ok(UntaggedValue::Primitive(Primitive::Decimal(result)))
558            }
559            (Primitive::Date(x), Primitive::Date(y)) => match operator {
560                Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::from(
561                    x.signed_duration_since(*y),
562                ))),
563                _ => Err((left.type_name(), right.type_name())),
564            },
565            (Primitive::Date(x), Primitive::Duration(_)) => {
566                let result = match operator {
567                    Operator::Plus => {
568                        // FIXME: Not sure if I could do something better with the Span.
569                        match Primitive::into_chrono_duration(rhs.clone(), Span::unknown()) {
570                            Ok(y) => match x.checked_add_signed(y) {
571                                Some(value) => Ok(value),
572                                None => Err(("Date", "Duration and date addition overflow")),
573                            },
574                            Err(_) => Err(("Date", "Duration overflow")),
575                        }
576                    }
577                    Operator::Minus => {
578                        match Primitive::into_chrono_duration(rhs.clone(), Span::unknown()) {
579                            Ok(y) => match x.checked_sub_signed(y) {
580                                Some(value) => Ok(value),
581                                None => Err(("Date", "Duration and date addition overflow")),
582                            },
583                            Err(_) => Err(("Date", "Duration overflow")),
584                        }
585                    }
586                    _ => Err((left.type_name(), right.type_name())),
587                }?;
588                Ok(UntaggedValue::Primitive(Primitive::Date(result)))
589            }
590            (Primitive::Duration(x), Primitive::Duration(y)) => {
591                let result = match operator {
592                    Operator::Plus => Ok(x + y),
593                    Operator::Minus => Ok(x - y),
594                    _ => Err((left.type_name(), right.type_name())),
595                }?;
596
597                Ok(UntaggedValue::Primitive(Primitive::Duration(result)))
598            }
599            (Primitive::Int(x), Primitive::Duration(y)) => {
600                let result = match operator {
601                    Operator::Plus => Ok(x + y),
602                    Operator::Minus => Ok(x - y),
603                    _ => Err((left.type_name(), right.type_name())),
604                }?;
605
606                Ok(UntaggedValue::Primitive(Primitive::Duration(result)))
607            }
608            (Primitive::Duration(x), Primitive::Decimal(y)) => {
609                let result = match operator {
610                    Operator::Divide => {
611                        if y.is_zero() {
612                            return Ok(zero_division_error());
613                        }
614
615                        let y = y.as_bigint_and_exponent();
616                        Ok(x / y.0)
617                    }
618                    _ => Err((left.type_name(), right.type_name())),
619                }?;
620
621                Ok(UntaggedValue::Primitive(Primitive::Duration(result)))
622            }
623            (Primitive::String(x), Primitive::String(y)) => {
624                let mut new_string = x.clone();
625                new_string.push_str(y);
626                Ok(UntaggedValue::Primitive(Primitive::String(new_string)))
627            }
628            _ => Err((left.type_name(), right.type_name())),
629        },
630        _ => Err((left.type_name(), right.type_name())),
631    }
632}
633
634/// If left is {{ Operator }} right
635pub fn compare_values(
636    operator: Operator,
637    left: &UntaggedValue,
638    right: &UntaggedValue,
639) -> Result<bool, (&'static str, &'static str)> {
640    let coerced = coerce_compare(left, right)?;
641    let ordering = coerced.compare();
642
643    use std::cmp::Ordering;
644
645    let result = matches!(
646        (operator, ordering),
647        (Operator::Equal, Ordering::Equal)
648            | (Operator::GreaterThan, Ordering::Greater)
649            | (Operator::GreaterThanOrEqual, Ordering::Greater)
650            | (Operator::GreaterThanOrEqual, Ordering::Equal)
651            | (Operator::LessThan, Ordering::Less)
652            | (Operator::LessThanOrEqual, Ordering::Less)
653            | (Operator::LessThanOrEqual, Ordering::Equal)
654            | (Operator::NotEqual, Ordering::Greater)
655            | (Operator::NotEqual, Ordering::Less)
656    );
657
658    Ok(result)
659}
660
661pub fn plain_type<'a>(value: impl Into<&'a UntaggedValue>, width: usize) -> String {
662    Type::from_value(value.into()).plain_string(width)
663}
664
665pub fn format_type<'a>(value: impl Into<&'a UntaggedValue>, width: usize) -> String {
666    Type::from_value(value.into()).colored_string(width)
667}
668
669pub fn format_leaf<'a>(value: impl Into<&'a UntaggedValue>) -> DebugDocBuilder {
670    InlineShape::from_value(value.into()).format().pretty()
671}
672
673pub fn style_leaf<'a>(
674    value: impl Into<&'a UntaggedValue>,
675    color_hash_map: &HashMap<String, nu_ansi_term::Style>,
676) -> TextStyle {
677    match value.into() {
678        UntaggedValue::Primitive(p) => {
679            // This is just to return the name of the type so that style_primitive
680            // can work on a string versus a type like String("some_text")
681            let str: &str = &p.to_string();
682            let str_len = str.len();
683            let paren_index = str.find('(').unwrap_or(str_len - 1);
684            let prim_type = str[0..paren_index].to_string();
685            style_primitive(&prim_type, color_hash_map)
686        }
687        _ => TextStyle::basic_left(),
688    }
689}
690
691pub fn format_for_column<'a>(
692    value: impl Into<&'a UntaggedValue>,
693    column: impl Into<Column>,
694) -> DebugDocBuilder {
695    InlineShape::from_value(value.into())
696        .format_for_column(column)
697        .pretty()
698}
699
700#[cfg(test)]
701mod tests {
702    use super::Date as d;
703    use super::UntaggedValue as v;
704    use super::{compute_values, merge_values};
705    use nu_protocol::hir::Operator;
706    use nu_protocol::{Primitive, UntaggedValue};
707    use nu_source::TaggedItem;
708
709    use indexmap::indexmap;
710
711    #[test]
712    fn merges_tables() {
713        let (author_1_date, author_2_date) = (
714            "2020-04-29".to_string().tagged_unknown(),
715            "2019-10-10".to_string().tagged_unknown(),
716        );
717
718        let table_author_row = v::row(indexmap! {
719            "name".into() => v::string("Andrés").into_untagged_value(),
720            "country".into() => v::string("EC").into_untagged_value(),
721            "date".into() => d::naive_from_str(author_1_date.borrow_tagged()).unwrap().into_untagged_value()
722        });
723
724        let other_table_author_row = v::row(indexmap! {
725            "name".into() => v::string("YK").into_untagged_value(),
726            "country".into() => v::string("US").into_untagged_value(),
727            "date".into() => d::naive_from_str(author_2_date.borrow_tagged()).unwrap().into_untagged_value()
728        });
729
730        assert_eq!(
731            other_table_author_row,
732            merge_values(&table_author_row, &other_table_author_row).unwrap()
733        );
734    }
735
736    #[test]
737    fn pow_operator_negatives_and_decimals() {
738        // test 2 ** 2
739        let result_one = compute_values(
740            Operator::Pow,
741            &UntaggedValue::Primitive(Primitive::Int(2)),
742            &UntaggedValue::Primitive(Primitive::Int(2)),
743        );
744
745        assert_eq!(
746            result_one.unwrap(),
747            UntaggedValue::Primitive(Primitive::Int(4))
748        );
749
750        // test 2 ** 2.0
751        let rhs_decimal = bigdecimal::FromPrimitive::from_f64(2.0).unwrap();
752
753        let result_two = compute_values(
754            Operator::Pow,
755            &UntaggedValue::Primitive(Primitive::Int(2)),
756            &UntaggedValue::Primitive(Primitive::Decimal(rhs_decimal)),
757        );
758
759        let should_equal_four_decimal = bigdecimal::FromPrimitive::from_f64(4.0).unwrap();
760
761        assert_eq!(
762            result_two.unwrap(),
763            UntaggedValue::Primitive(Primitive::Decimal(should_equal_four_decimal))
764        );
765
766        // test 2.0 ** 2.0
767        let rhs_decimal = bigdecimal::FromPrimitive::from_f64(2.0).unwrap();
768        let lhs_decimal = bigdecimal::FromPrimitive::from_f64(2.0).unwrap();
769        let should_equal_four_decimal = bigdecimal::FromPrimitive::from_f64(4.0).unwrap();
770
771        let result_three = compute_values(
772            Operator::Pow,
773            &UntaggedValue::Primitive(Primitive::Decimal(lhs_decimal)),
774            &UntaggedValue::Primitive(Primitive::Decimal(rhs_decimal)),
775        );
776
777        assert_eq!(
778            result_three.unwrap(),
779            UntaggedValue::Primitive(Primitive::Decimal(should_equal_four_decimal))
780        );
781
782        // test 2 ** -2
783        let result_four = compute_values(
784            Operator::Pow,
785            &UntaggedValue::Primitive(Primitive::Int(2)),
786            &UntaggedValue::Primitive(Primitive::Int(-2)),
787        );
788
789        let should_equal_zero_decimal = bigdecimal::FromPrimitive::from_f64(0.25).unwrap();
790
791        assert_eq!(
792            result_four.unwrap(),
793            UntaggedValue::Primitive(Primitive::Decimal(should_equal_zero_decimal))
794        );
795
796        // test -2 ** -2
797        let result_five = compute_values(
798            Operator::Pow,
799            &UntaggedValue::Primitive(Primitive::Int(-2)),
800            &UntaggedValue::Primitive(Primitive::Int(-2)),
801        );
802
803        let should_equal_neg_zero_decimal = bigdecimal::FromPrimitive::from_f64(-0.25).unwrap();
804
805        assert_eq!(
806            result_five.unwrap(),
807            UntaggedValue::Primitive(Primitive::Decimal(should_equal_neg_zero_decimal))
808        );
809
810        // test -2 ** 2
811        let result_six = compute_values(
812            Operator::Pow,
813            &UntaggedValue::Primitive(Primitive::Int(-2)),
814            &UntaggedValue::Primitive(Primitive::Int(2)),
815        );
816
817        assert_eq!(
818            result_six.unwrap(),
819            UntaggedValue::Primitive(Primitive::Int(-4))
820        );
821
822        // test -2.0 ** 2
823        let lhs_decimal = bigdecimal::FromPrimitive::from_f64(-2.0).unwrap();
824        let should_equal_neg_four_decimal = bigdecimal::FromPrimitive::from_f64(-4.0).unwrap();
825
826        let result_seven = compute_values(
827            Operator::Pow,
828            &UntaggedValue::Primitive(Primitive::Decimal(lhs_decimal)),
829            &UntaggedValue::Primitive(Primitive::Int(2)),
830        );
831
832        // Need to validate
833        assert_eq!(
834            result_seven.unwrap(),
835            UntaggedValue::Primitive(Primitive::Decimal(should_equal_neg_four_decimal))
836        );
837    }
838}