mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 19:37:45 +02:00
Shrink the size of Expr
(#12610)
# Description Continuing from #12568, this PR further reduces the size of `Expr` from 64 to 40 bytes. It also reduces `Expression` from 128 to 96 bytes and `Type` from 32 to 24 bytes. This was accomplished by: - for `Expr` with multiple fields (e.g., `Expr::Thing(A, B, C)`), merging the fields into new AST struct types and then boxing this struct (e.g. `Expr::Thing(Box<ABC>)`). - replacing `Vec<T>` with `Box<[T]>` in multiple places. `Expr`s and `Expression`s should rarely be mutated, if at all, so this optimization makes sense. By reducing the size of these types, I didn't notice a large performance improvement (at least compared to #12568). But this PR does reduce the memory usage of nushell. My config is somewhat light so I only noticed a difference of 1.4MiB (38.9MiB vs 37.5MiB). --------- Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
This commit is contained in:
@ -7,7 +7,7 @@ use std::sync::Arc;
|
||||
|
||||
/// convert a raw string representation of NUON data to an actual Nushell [`Value`]
|
||||
///
|
||||
/// > **Note**
|
||||
/// > **Note**
|
||||
/// > [`Span`] can be passed to [`from_nuon`] if there is context available to the caller, e.g. when
|
||||
/// > using this function in a command implementation such as
|
||||
/// [`from nuon`](https://www.nushell.sh/commands/docs/from_nuon.html).
|
||||
@ -197,10 +197,13 @@ fn convert_to_value(
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::Int(val) => Ok(Value::int(val, span)),
|
||||
Expr::Keyword(kw, ..) => Err(ShellError::OutsideSpannedLabeledError {
|
||||
Expr::Keyword(kw) => Err(ShellError::OutsideSpannedLabeledError {
|
||||
src: original_text.to_string(),
|
||||
error: "Error when loading".into(),
|
||||
msg: format!("{} not supported in nuon", String::from_utf8_lossy(&kw)),
|
||||
msg: format!(
|
||||
"{} not supported in nuon",
|
||||
String::from_utf8_lossy(&kw.keyword)
|
||||
),
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::List(vals) => {
|
||||
@ -237,27 +240,27 @@ fn convert_to_value(
|
||||
msg: "operators not supported in nuon".into(),
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::Range(from, next, to, operator) => {
|
||||
let from = if let Some(f) = from {
|
||||
convert_to_value(*f, span, original_text)?
|
||||
Expr::Range(range) => {
|
||||
let from = if let Some(f) = range.from {
|
||||
convert_to_value(f, span, original_text)?
|
||||
} else {
|
||||
Value::nothing(expr.span)
|
||||
};
|
||||
|
||||
let next = if let Some(s) = next {
|
||||
convert_to_value(*s, span, original_text)?
|
||||
let next = if let Some(s) = range.next {
|
||||
convert_to_value(s, span, original_text)?
|
||||
} else {
|
||||
Value::nothing(expr.span)
|
||||
};
|
||||
|
||||
let to = if let Some(t) = to {
|
||||
convert_to_value(*t, span, original_text)?
|
||||
let to = if let Some(t) = range.to {
|
||||
convert_to_value(t, span, original_text)?
|
||||
} else {
|
||||
Value::nothing(expr.span)
|
||||
};
|
||||
|
||||
Ok(Value::range(
|
||||
Range::new(from, next, to, operator.inclusion, expr.span)?,
|
||||
Range::new(from, next, to, range.operator.inclusion, expr.span)?,
|
||||
expr.span,
|
||||
))
|
||||
}
|
||||
@ -329,12 +332,12 @@ fn convert_to_value(
|
||||
msg: "subexpressions not supported in nuon".into(),
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::Table(mut headers, cells) => {
|
||||
Expr::Table(mut table) => {
|
||||
let mut cols = vec![];
|
||||
|
||||
let mut output = vec![];
|
||||
|
||||
for key in headers.iter_mut() {
|
||||
for key in table.columns.as_mut() {
|
||||
let key_str = match &mut key.expr {
|
||||
Expr::String(key_str) => key_str,
|
||||
_ => {
|
||||
@ -351,14 +354,14 @@ fn convert_to_value(
|
||||
return Err(ShellError::ColumnDefinedTwice {
|
||||
col_name: key_str.clone(),
|
||||
second_use: key.span,
|
||||
first_use: headers[idx].span,
|
||||
first_use: table.columns[idx].span,
|
||||
});
|
||||
} else {
|
||||
cols.push(std::mem::take(key_str));
|
||||
}
|
||||
}
|
||||
|
||||
for row in cells {
|
||||
for row in table.rows.into_vec() {
|
||||
if cols.len() != row.len() {
|
||||
return Err(ShellError::OutsideSpannedLabeledError {
|
||||
src: original_text.to_string(),
|
||||
@ -370,7 +373,7 @@ fn convert_to_value(
|
||||
|
||||
let record = cols
|
||||
.iter()
|
||||
.zip(row)
|
||||
.zip(row.into_vec())
|
||||
.map(|(col, cell)| {
|
||||
convert_to_value(cell, span, original_text).map(|val| (col.clone(), val))
|
||||
})
|
||||
@ -381,8 +384,8 @@ fn convert_to_value(
|
||||
|
||||
Ok(Value::list(output, span))
|
||||
}
|
||||
Expr::ValueWithUnit(val, unit) => {
|
||||
let size = match val.expr {
|
||||
Expr::ValueWithUnit(value) => {
|
||||
let size = match value.expr.expr {
|
||||
Expr::Int(val) => val,
|
||||
_ => {
|
||||
return Err(ShellError::OutsideSpannedLabeledError {
|
||||
@ -394,7 +397,7 @@ fn convert_to_value(
|
||||
}
|
||||
};
|
||||
|
||||
match unit.item {
|
||||
match value.unit.item {
|
||||
Unit::Byte => Ok(Value::filesize(size, span)),
|
||||
Unit::Kilobyte => Ok(Value::filesize(size * 1000, span)),
|
||||
Unit::Megabyte => Ok(Value::filesize(size * 1000 * 1000, span)),
|
||||
|
Reference in New Issue
Block a user