nushell/crates/nu-protocol/src
Reilly Wood 3b5172a8fa
LazyRecord (#7619)
This is an attempt to implement a new `Value::LazyRecord` variant for
performance reasons.

`LazyRecord` is like a regular `Record`, but it's possible to access
individual columns without evaluating other columns. I've implemented
`LazyRecord` for the special `$nu` variable; accessing `$nu` is
relatively slow because of all the information in `scope`, and [`$nu`
accounts for about 2/3 of Nu's startup time on
Linux](https://github.com/nushell/nushell/issues/6677#issuecomment-1364618122).

### Benchmarks

I ran some benchmarks on my desktop (Linux, 12900K) and the results are
very pleasing.

Nu's time to start up and run a command (`cargo build --release;
hyperfine 'target/release/nu -c "echo \"Hello, world!\""' --shell=none
--warmup 10`) goes from **8.8ms to 3.2ms, about 2.8x faster**.

Tests are also much faster! Running `cargo nextest` (with our very slow
`proptest` tests disabled) goes from **7.2s to 4.4s (1.6x faster)**,
because most tests involve launching a new instance of Nu.

### Design (updated)

I've added a new `LazyRecord` trait and added a `Value` variant wrapping
those trait objects, much like `CustomValue`. `LazyRecord`
implementations must implement these 2 functions:

```rust
// All column names
fn column_names(&self) -> Vec<&'static str>;

// Get 1 specific column value
fn get_column_value(&self, column: &str) -> Result<Value, ShellError>;
 ```

### Serializability

`Value` variants must implement `Serializable` and `Deserializable`, which poses some problems because I want to use unserializable things like `EngineState` in `LazyRecord`s. To work around this, I basically lie to the type system:

1. Add `#[typetag::serde(tag = "type")]` to `LazyRecord` to make it serializable
2. Any unserializable fields in `LazyRecord` implementations get marked with `#[serde(skip)]`
3. At the point where a `LazyRecord` normally would get serialized and sent to a plugin, I instead collect it into a regular `Value::Record` (which can be serialized)
2023-01-18 19:27:26 -08:00
..
ast Support redirect err and out to different streams (#7685) 2023-01-12 10:22:30 +01:00
engine Fix typos and use more idiomatic assertions (#7755) 2023-01-15 15:03:32 +13:00
value LazyRecord (#7619) 2023-01-18 19:27:26 -08:00
cli_error.rs Clippy fix for Rust 1.63 (#6299) 2022-08-11 11:54:54 -05:00
config.rs Add cursor shape configuration for each edit mode (#7745) 2023-01-13 14:37:39 -06:00
example.rs Start support for commandline args to nu itself (#851) 2022-01-27 01:42:39 +11:00
exportable.rs Removes export env command (#6468) 2022-09-25 19:52:43 +03:00
id.rs Overlays (#5375) 2022-05-08 07:39:22 +12:00
lev_distance.rs Improve "Did you mean?" suggestions (#6579) 2022-09-20 19:46:01 -05:00
lib.rs Add cursor shape configuration for each edit mode (#7745) 2023-01-13 14:37:39 -06:00
module.rs Removes export env command (#6468) 2022-09-25 19:52:43 +03:00
pipeline_data.rs fix some typos (#7773) 2023-01-16 12:43:46 +01:00
shell_error.rs LazyRecord (#7619) 2023-01-18 19:27:26 -08:00
signature.rs Expand Nushell's help system (#7611) 2022-12-30 17:44:37 +02:00
span.rs Protocol: debug_assert!() Span to reflect a valid slice (#6806) 2022-12-03 11:44:12 +02:00
syntax_shape.rs sort enums add missing items to parse_shape_name (#7450) 2022-12-13 10:46:22 -06:00
ty.rs sort enums add missing items to parse_shape_name (#7450) 2022-12-13 10:46:22 -06:00
util.rs move BufferedReader out of nu-command (#7697) 2023-01-06 15:22:17 -08:00
variable.rs Limited mutable variables (#7089) 2022-11-11 19:51:08 +13:00