Make the default int an i64 (#3428)

* Make the default int an i64

* fmt

* Fix random integer

* Treat pids as i64 for now
This commit is contained in:
JT
2021-05-14 20:35:09 +12:00
committed by GitHub
parent 440a589f9e
commit d79a3130b8
59 changed files with 693 additions and 284 deletions

View File

@ -10,18 +10,18 @@ use crate::{hir, Dictionary, PositionalType, Primitive, SyntaxShape, UntaggedVal
use crate::{PathMember, ShellTypeName};
use derive_new::new;
use nu_errors::ParseError;
use nu_errors::{ParseError, ShellError};
use nu_source::{
DbgDocBldr, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugRefineKind, PrettyDebugWithSource,
};
use nu_source::{IntoSpanned, Span, Spanned, SpannedItem, Tag};
use bigdecimal::BigDecimal;
use bigdecimal::{BigDecimal, ToPrimitive};
use indexmap::IndexMap;
use log::trace;
use num_bigint::{BigInt, ToBigInt};
use num_traits::identities::Zero;
use num_traits::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct InternalCommand {
@ -363,7 +363,7 @@ pub enum Unit {
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Deserialize, Serialize)]
pub enum Member {
String(/* outer */ Span, /* inner */ Span),
Int(BigInt, Span),
Int(i64, Span),
Bare(Spanned<String>),
}
@ -371,7 +371,7 @@ impl Member {
pub fn to_path_member(&self) -> PathMember {
match self {
//Member::String(outer, inner) => PathMember::string(inner.slice(source), *outer),
Member::Int(int, span) => PathMember::int(int.clone(), *span),
Member::Int(int, span) => PathMember::int(*int, *span),
Member::Bare(spanned_string) => {
PathMember::string(spanned_string.item.clone(), spanned_string.span)
}
@ -402,13 +402,32 @@ impl HasSpan for Member {
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Deserialize, Serialize)]
pub enum Number {
Int(BigInt),
BigInt(BigInt),
Int(i64),
Decimal(BigDecimal),
}
impl Number {
pub fn to_i64(&self) -> Result<i64, ShellError> {
match self {
Number::BigInt(bi) => match bi.to_i64() {
Some(i) => Ok(i),
None => Err(ShellError::untagged_runtime_error(
"Cannot convert bigint to i64, too large",
)),
},
Number::Int(i) => Ok(*i),
Number::Decimal(_) => Err(ShellError::untagged_runtime_error(
"Cannont convert decimal to i64",
)),
}
}
}
impl PrettyDebug for Number {
fn pretty(&self) -> DebugDocBuilder {
match self {
Number::BigInt(int) => DbgDocBldr::primitive(int),
Number::Int(int) => DbgDocBldr::primitive(int),
Number::Decimal(decimal) => DbgDocBldr::primitive(decimal),
}
@ -420,13 +439,13 @@ macro_rules! primitive_int {
$(
impl From<$ty> for Number {
fn from(int: $ty) -> Number {
Number::Int(BigInt::zero() + int)
Number::BigInt(BigInt::zero() + int)
}
}
impl From<&$ty> for Number {
fn from(int: &$ty) -> Number {
Number::Int(BigInt::zero() + *int)
Number::BigInt(BigInt::zero() + *int)
}
}
)*
@ -469,8 +488,13 @@ impl std::ops::Mul for Number {
fn mul(self, other: Number) -> Number {
match (self, other) {
(Number::Int(a), Number::Int(b)) => Number::Int(a * b),
(Number::BigInt(a), Number::Int(b)) => Number::BigInt(a * BigInt::from(b)),
(Number::Int(a), Number::BigInt(b)) => Number::BigInt(BigInt::from(a) * b),
(Number::BigInt(a), Number::BigInt(b)) => Number::BigInt(a * b),
(Number::Int(a), Number::Decimal(b)) => Number::Decimal(BigDecimal::from(a) * b),
(Number::Decimal(a), Number::Int(b)) => Number::Decimal(a * BigDecimal::from(b)),
(Number::BigInt(a), Number::Decimal(b)) => Number::Decimal(BigDecimal::from(a) * b),
(Number::Decimal(a), Number::BigInt(b)) => Number::Decimal(a * BigDecimal::from(b)),
(Number::Decimal(a), Number::Decimal(b)) => Number::Decimal(a * b),
}
}
@ -482,6 +506,7 @@ impl std::ops::Mul<u32> for Number {
fn mul(self, other: u32) -> Number {
match self {
Number::BigInt(left) => Number::BigInt(left * (other as i64)),
Number::Int(left) => Number::Int(left * (other as i64)),
Number::Decimal(left) => Number::Decimal(left * BigDecimal::from(other)),
}
@ -491,7 +516,8 @@ impl std::ops::Mul<u32> for Number {
impl ToBigInt for Number {
fn to_bigint(&self) -> Option<BigInt> {
match self {
Number::Int(int) => Some(int.clone()),
Number::Int(int) => Some(BigInt::from(*int)),
Number::BigInt(int) => Some(int.clone()),
// The BigDecimal to BigInt conversion always return Some().
// FIXME: This conversion might not be want we want, it just remove the scale.
Number::Decimal(decimal) => decimal.to_bigint(),
@ -505,25 +531,6 @@ impl PrettyDebug for Unit {
}
}
pub fn convert_number_to_u64(number: &Number) -> u64 {
match number {
Number::Int(big_int) => {
if let Some(x) = big_int.to_u64() {
x
} else {
unreachable!("Internal error: convert_number_to_u64 given incompatible number")
}
}
Number::Decimal(big_decimal) => {
if let Some(x) = big_decimal.to_u64() {
x
} else {
unreachable!("Internal error: convert_number_to_u64 given incompatible number")
}
}
}
}
impl Unit {
pub fn as_str(self) -> &'static str {
match self {
@ -553,22 +560,18 @@ impl Unit {
let size = size.clone();
match self {
Unit::Byte => filesize(convert_number_to_u64(&size)),
Unit::Kilobyte => filesize(convert_number_to_u64(&size) * 1000),
Unit::Megabyte => filesize(convert_number_to_u64(&size) * 1000 * 1000),
Unit::Gigabyte => filesize(convert_number_to_u64(&size) * 1000 * 1000 * 1000),
Unit::Terabyte => filesize(convert_number_to_u64(&size) * 1000 * 1000 * 1000 * 1000),
Unit::Petabyte => {
filesize(convert_number_to_u64(&size) * 1000 * 1000 * 1000 * 1000 * 1000)
}
Unit::Byte => filesize(size),
Unit::Kilobyte => filesize(size * 1000),
Unit::Megabyte => filesize(size * 1000 * 1000),
Unit::Gigabyte => filesize(size * 1000 * 1000 * 1000),
Unit::Terabyte => filesize(size * 1000 * 1000 * 1000 * 1000),
Unit::Petabyte => filesize(size * 1000 * 1000 * 1000 * 1000 * 1000),
Unit::Kibibyte => filesize(convert_number_to_u64(&size) * 1024),
Unit::Mebibyte => filesize(convert_number_to_u64(&size) * 1024 * 1024),
Unit::Gibibyte => filesize(convert_number_to_u64(&size) * 1024 * 1024 * 1024),
Unit::Tebibyte => filesize(convert_number_to_u64(&size) * 1024 * 1024 * 1024 * 1024),
Unit::Pebibyte => {
filesize(convert_number_to_u64(&size) * 1024 * 1024 * 1024 * 1024 * 1024)
}
Unit::Kibibyte => filesize(size * 1024),
Unit::Mebibyte => filesize(size * 1024 * 1024),
Unit::Gibibyte => filesize(size * 1024 * 1024 * 1024),
Unit::Tebibyte => filesize(size * 1024 * 1024 * 1024 * 1024),
Unit::Pebibyte => filesize(size * 1024 * 1024 * 1024 * 1024 * 1024),
Unit::Nanosecond => duration(size.to_bigint().expect("Conversion should never fail.")),
Unit::Microsecond => {
@ -614,8 +617,19 @@ impl Unit {
}
}
pub fn filesize(size_in_bytes: impl Into<BigInt>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Filesize(size_in_bytes.into()))
pub fn filesize(size_in_bytes: Number) -> UntaggedValue {
match size_in_bytes {
Number::Int(i) => UntaggedValue::Primitive(Primitive::Filesize(i as u64)),
Number::BigInt(bi) => match bi.to_u64() {
Some(i) => UntaggedValue::Primitive(Primitive::Filesize(i)),
None => UntaggedValue::Error(ShellError::untagged_runtime_error(
"Big int too large to convert to filesize",
)),
},
Number::Decimal(_) => UntaggedValue::Error(ShellError::untagged_runtime_error(
"Decimal can't convert to filesize",
)),
}
}
pub fn duration(nanos: BigInt) -> UntaggedValue {
@ -1069,10 +1083,14 @@ impl IntoSpanned for Expression {
}
impl Expression {
pub fn integer(i: BigInt) -> Expression {
pub fn integer(i: i64) -> Expression {
Expression::Literal(Literal::Number(Number::Int(i)))
}
pub fn big_integer(i: BigInt) -> Expression {
Expression::Literal(Literal::Number(Number::BigInt(i)))
}
pub fn decimal(dec: BigDecimal) -> Expression {
Expression::Literal(Literal::Number(Number::Decimal(dec)))
}
@ -1116,7 +1134,7 @@ impl Expression {
pub fn unit(i: Spanned<i64>, unit: Spanned<Unit>) -> Expression {
Expression::Literal(Literal::Size(
Number::Int(BigInt::from(i.item)).spanned(i.span),
Number::BigInt(BigInt::from(i.item)).spanned(i.span),
unit,
))
}

View File

@ -30,6 +30,8 @@ pub enum Type {
Nothing,
/// An integer-based value
Int,
/// An big integer-based value
BigInt,
/// A range between two values
Range(Box<RangeType>),
/// A decimal (floating point) value
@ -131,6 +133,7 @@ impl Type {
match primitive {
Primitive::Nothing => Type::Nothing,
Primitive::Int(_) => Type::Int,
Primitive::BigInt(_) => Type::BigInt,
Primitive::Range(range) => {
let (left_value, left_inclusion) = &range.from;
let (right_value, right_inclusion) = &range.to;
@ -199,6 +202,7 @@ impl PrettyDebug for Type {
match self {
Type::Nothing => ty("nothing"),
Type::Int => ty("integer"),
Type::BigInt => ty("big integer"),
Type::Range(range) => {
let (left, left_inclusion) = &range.from;
let (right, right_inclusion) = &range.to;

View File

@ -178,10 +178,15 @@ impl UntaggedValue {
}
/// Helper for creating integer values
pub fn int(i: impl Into<BigInt>) -> UntaggedValue {
pub fn int(i: impl Into<i64>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Int(i.into()))
}
/// Helper for creating big integer values
pub fn big_int(i: impl Into<BigInt>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::BigInt(i.into()))
}
/// Helper for creating glob pattern values
pub fn glob_pattern(s: impl Into<String>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::String(s.into()))
@ -193,8 +198,8 @@ impl UntaggedValue {
}
/// Helper for creating filesize values
pub fn filesize(s: impl Into<BigInt>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Filesize(s.into()))
pub fn filesize(s: u64) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Filesize(s))
}
/// Helper for creating decimal values
@ -339,22 +344,30 @@ impl Value {
}
}
/// View the Value as a Int (BigInt), if possible
pub fn as_int(&self) -> Result<BigInt, ShellError> {
/// View the Value as a Int, if possible
pub fn as_int(&self) -> Result<i64, ShellError> {
match &self.value {
UntaggedValue::Primitive(Primitive::Int(n)) => Ok(n.clone()),
UntaggedValue::Primitive(Primitive::Int(n)) => Ok(*n),
_ => Err(ShellError::type_error("bigint", self.spanned_type_name())),
}
}
/// View the Value as a Filesize (BigInt), if possible
pub fn as_filesize(&self) -> Result<BigInt, ShellError> {
/// View the Value as a Int, if possible
pub fn as_big_int(&self) -> Result<BigInt, ShellError> {
match &self.value {
UntaggedValue::Primitive(Primitive::Filesize(fs)) => Ok(fs.clone()),
UntaggedValue::Primitive(Primitive::BigInt(n)) => Ok(n.clone()),
_ => Err(ShellError::type_error("bigint", self.spanned_type_name())),
}
}
/// View the Value as a Filesize (u64), if possible
pub fn as_filesize(&self) -> Result<u64, ShellError> {
match &self.value {
UntaggedValue::Primitive(Primitive::Filesize(fs)) => Ok(*fs),
_ => Err(ShellError::type_error("int", self.spanned_type_name())),
}
}
/// View the Value as a Duration (BigInt), if possible
pub fn as_duration(&self) -> Result<BigInt, ShellError> {
match &self.value {
@ -808,8 +821,6 @@ pub trait U64Ext {
fn to_untagged_value(&self) -> UntaggedValue;
fn to_value(&self, tag: Tag) -> Value;
fn to_value_create_tag(&self) -> Value;
fn to_filesize_untagged_value(&self) -> UntaggedValue;
fn to_filesize_value(&self, tag: Tag) -> Value;
fn to_duration_untagged_value(&self) -> UntaggedValue;
fn to_duration_value(&self, tag: Tag) -> Value;
}
@ -817,14 +828,7 @@ pub trait U64Ext {
impl U64Ext for u64 {
fn to_value(&self, the_tag: Tag) -> Value {
Value {
value: UntaggedValue::Primitive(Primitive::Int(BigInt::from(*self))),
tag: the_tag,
}
}
fn to_filesize_value(&self, the_tag: Tag) -> Value {
Value {
value: UntaggedValue::Primitive(Primitive::Filesize(BigInt::from(*self))),
value: UntaggedValue::Primitive(Primitive::BigInt(BigInt::from(*self))),
tag: the_tag,
}
}
@ -839,7 +843,7 @@ impl U64Ext for u64 {
fn to_value_create_tag(&self) -> Value {
let end = self.to_string().len();
Value {
value: UntaggedValue::Primitive(Primitive::Int(BigInt::from(*self))),
value: UntaggedValue::Primitive(Primitive::BigInt(BigInt::from(*self))),
tag: Tag {
anchor: None,
span: Span::new(0, end),
@ -848,11 +852,7 @@ impl U64Ext for u64 {
}
fn to_untagged_value(&self) -> UntaggedValue {
UntaggedValue::int(*self)
}
fn to_filesize_untagged_value(&self) -> UntaggedValue {
UntaggedValue::filesize(*self)
UntaggedValue::big_int(*self)
}
fn to_duration_untagged_value(&self) -> UntaggedValue {
@ -869,7 +869,7 @@ pub trait I64Ext {
impl I64Ext for i64 {
fn to_value(&self, the_tag: Tag) -> Value {
Value {
value: UntaggedValue::Primitive(Primitive::Int(BigInt::from(*self))),
value: UntaggedValue::Primitive(Primitive::Int(*self)),
tag: the_tag,
}
}
@ -877,7 +877,7 @@ impl I64Ext for i64 {
fn to_value_create_tag(&self) -> Value {
let end = self.to_string().len();
Value {
value: UntaggedValue::Primitive(Primitive::Int(BigInt::from(*self))),
value: UntaggedValue::Primitive(Primitive::Int(*self)),
tag: Tag {
anchor: None,
span: Span::new(0, end),

View File

@ -4,7 +4,6 @@ use nu_source::{
span_for_spanned_list, DbgDocBldr, DebugDocBuilder, HasFallibleSpan, PrettyDebug, Span,
Spanned, SpannedItem,
};
use num_bigint::BigInt;
use serde::{Deserialize, Serialize};
use crate::hir::{Expression, Literal, Member, SpannedExpression};
@ -14,7 +13,7 @@ use nu_errors::ParseError;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum UnspannedPathMember {
String(String),
Int(BigInt),
Int(i64),
}
impl UnspannedPathMember {
@ -125,8 +124,8 @@ impl PathMember {
}
/// Create a numeric path member
pub fn int(int: impl Into<BigInt>, span: impl Into<Span>) -> PathMember {
UnspannedPathMember::Int(int.into()).into_path_member(span)
pub fn int(int: i64, span: impl Into<Span>) -> PathMember {
UnspannedPathMember::Int(int).into_path_member(span)
}
pub fn as_string(&self) -> String {
@ -160,8 +159,8 @@ fn parse(raw_column_path: &Spanned<String>) -> (SpannedExpression, Option<ParseE
raw_column_path.span.start() + idx,
);
if let Ok(row_number) = current_part.parse::<u64>() {
output.push(Member::Int(BigInt::from(row_number), part_span));
if let Ok(row_number) = current_part.parse::<i64>() {
output.push(Member::Int(row_number, part_span));
} else {
let trimmed = trim_quotes(&current_part);
output.push(Member::Bare(trimmed.clone().spanned(part_span)));
@ -180,8 +179,8 @@ fn parse(raw_column_path: &Spanned<String>) -> (SpannedExpression, Option<ParseE
raw_column_path.span.start() + start_index,
raw_column_path.span.start() + last_index + 1,
);
if let Ok(row_number) = current_part.parse::<u64>() {
output.push(Member::Int(BigInt::from(row_number), part_span));
if let Ok(row_number) = current_part.parse::<i64>() {
output.push(Member::Int(row_number, part_span));
} else {
let current_part = trim_quotes(&current_part);
output.push(Member::Bare(current_part.spanned(part_span)));

View File

@ -11,7 +11,8 @@ impl std::convert::TryFrom<&Value> for i64 {
/// Convert to an i64 integer, if possible
fn try_from(value: &Value) -> Result<i64, ShellError> {
match &value.value {
UntaggedValue::Primitive(Primitive::Int(int)) => {
UntaggedValue::Primitive(Primitive::Int(int)) => Ok(*int),
UntaggedValue::Primitive(Primitive::BigInt(int)) => {
int.tagged(&value.tag).coerce_into("converting to i64")
}
_ => Err(ShellError::type_error("Integer", value.spanned_type_name())),

View File

@ -36,6 +36,7 @@ impl PrettyType for Primitive {
match self {
Primitive::Nothing => ty("nothing"),
Primitive::Int(_) => ty("integer"),
Primitive::BigInt(_) => ty("big-integer"),
Primitive::Range(_) => ty("range"),
Primitive::Decimal(_) => ty("decimal"),
Primitive::Filesize(_) => ty("filesize"),
@ -59,6 +60,7 @@ impl PrettyDebug for Primitive {
match self {
Primitive::Nothing => DbgDocBldr::primitive("nothing"),
Primitive::Int(int) => prim(format_args!("{}", int)),
Primitive::BigInt(int) => prim(format_args!("{}", int)),
Primitive::Decimal(decimal) => prim(format_args!("{}", decimal)),
Primitive::Range(range) => {
let (left, left_inclusion) = &range.from;

View File

@ -24,14 +24,16 @@ const NANOS_PER_SEC: u32 = 1_000_000_000;
pub enum Primitive {
/// An empty value
Nothing,
/// A common integer
Int(i64),
/// A "big int", an integer with arbitrarily large size (aka not limited to 64-bit)
#[serde(with = "serde_bigint")]
Int(BigInt),
BigInt(BigInt),
/// A "big decimal", an decimal number with arbitrarily large size (aka not limited to 64-bit)
#[serde(with = "serde_bigdecimal")]
Decimal(BigDecimal),
/// A count in the number of bytes, used as a filesize
Filesize(BigInt),
Filesize(u64),
/// A string value
String(String),
/// A path to travel to reach a value in a table
@ -351,7 +353,7 @@ impl From<BigDecimal> for Primitive {
impl From<BigInt> for Primitive {
/// Helper to convert from integers to a Primitive value
fn from(int: BigInt) -> Primitive {
Primitive::Int(int)
Primitive::BigInt(int)
}
}
@ -373,14 +375,14 @@ macro_rules! from_native_to_primitive {
};
}
from_native_to_primitive!(i8, Primitive::Int, BigInt::from_i8);
from_native_to_primitive!(i16, Primitive::Int, BigInt::from_i16);
from_native_to_primitive!(i32, Primitive::Int, BigInt::from_i32);
from_native_to_primitive!(i64, Primitive::Int, BigInt::from_i64);
from_native_to_primitive!(u8, Primitive::Int, BigInt::from_u8);
from_native_to_primitive!(u16, Primitive::Int, BigInt::from_u16);
from_native_to_primitive!(u32, Primitive::Int, BigInt::from_u32);
from_native_to_primitive!(u64, Primitive::Int, BigInt::from_u64);
from_native_to_primitive!(i8, Primitive::Int, i64::from_i8);
from_native_to_primitive!(i16, Primitive::Int, i64::from_i16);
from_native_to_primitive!(i32, Primitive::Int, i64::from_i32);
from_native_to_primitive!(i64, Primitive::Int, i64::from_i64);
from_native_to_primitive!(u8, Primitive::Int, i64::from_u8);
from_native_to_primitive!(u16, Primitive::Int, i64::from_u16);
from_native_to_primitive!(u32, Primitive::Int, i64::from_u32);
from_native_to_primitive!(u64, Primitive::BigInt, BigInt::from_u64);
from_native_to_primitive!(f32, Primitive::Decimal, BigDecimal::from_f32);
from_native_to_primitive!(f64, Primitive::Decimal, BigDecimal::from_f64);
@ -410,6 +412,7 @@ impl ShellTypeName for Primitive {
match self {
Primitive::Nothing => "nothing",
Primitive::Int(_) => "integer",
Primitive::BigInt(_) => "big integer",
Primitive::Range(_) => "range",
Primitive::Decimal(_) => "decimal",
Primitive::Filesize(_) => "filesize(in bytes)",
@ -454,6 +457,7 @@ pub fn format_primitive(primitive: &Primitive, field_name: Option<&String>) -> S
}
Primitive::Duration(duration) => format_duration(duration),
Primitive::Int(i) => i.to_string(),
Primitive::BigInt(i) => i.to_string(),
Primitive::Decimal(decimal) => {
// TODO: We should really pass the precision in here instead of hard coding it
let decimal_string = decimal.to_string();

View File

@ -68,6 +68,36 @@ impl Range {
}
}
pub fn min_i64(&self) -> Result<i64, ShellError> {
let (from, range_incl) = &self.from;
let minval = if let Primitive::Nothing = from.item {
0
} else {
from.item.as_i64(from.span)?
};
match range_incl {
RangeInclusion::Inclusive => Ok(minval),
RangeInclusion::Exclusive => Ok(minval.saturating_add(1)),
}
}
pub fn max_i64(&self) -> Result<i64, ShellError> {
let (to, range_incl) = &self.to;
let maxval = if let Primitive::Nothing = to.item {
i64::MAX
} else {
to.item.as_i64(to.span)?
};
match range_incl {
RangeInclusion::Inclusive => Ok(maxval),
RangeInclusion::Exclusive => Ok(maxval.saturating_sub(1)),
}
}
pub fn min_usize(&self) -> Result<usize, ShellError> {
let (from, range_incl) = &self.from;