diff --git a/crates/nu-cli/src/completions/command_completions.rs b/crates/nu-cli/src/completions/command_completions.rs index 413eaaf5a5..8cabd21334 100644 --- a/crates/nu-cli/src/completions/command_completions.rs +++ b/crates/nu-cli/src/completions/command_completions.rs @@ -229,7 +229,7 @@ pub fn find_non_whitespace_index(contents: &[u8], start: usize) -> usize { } } -pub fn is_passthrough_command(working_set_file_contents: &[(Vec, usize, usize)]) -> bool { +pub fn is_passthrough_command(working_set_file_contents: &[(Arc>, usize, usize)]) -> bool { for (contents, _, _) in working_set_file_contents { let last_pipe_pos_rev = contents.iter().rev().position(|x| x == &b'|'); let last_pipe_pos = last_pipe_pos_rev.map(|x| contents.len() - x).unwrap_or(0); diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index ac6d727bc1..af935c7992 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -124,9 +124,9 @@ impl NuCompleter { let output = parse(&mut working_set, Some("completer"), line.as_bytes(), false); - for pipeline in output.pipelines.into_iter() { - for pipeline_element in pipeline.elements { - let flattened = flatten_pipeline_element(&working_set, &pipeline_element); + for pipeline in output.pipelines.iter() { + for pipeline_element in &pipeline.elements { + let flattened = flatten_pipeline_element(&working_set, pipeline_element); let mut spans: Vec = vec![]; for (flat_idx, flat) in flattened.iter().enumerate() { diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index 349a4aece5..f2b6e0b520 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::util::eval_source; use log::info; use log::trace; @@ -117,7 +119,7 @@ pub fn evaluate_file( std::process::exit(1); } - for block in &mut working_set.delta.blocks { + for block in working_set.delta.blocks.iter_mut().map(Arc::make_mut) { if block.signature.name == "main" { block.signature.name = source_filename.to_string_lossy().to_string(); } else if block.signature.name.starts_with("main ") { diff --git a/crates/nu-cmd-base/src/hook.rs b/crates/nu-cmd-base/src/hook.rs index a5f13a4b2d..a608b47285 100644 --- a/crates/nu-cmd-base/src/hook.rs +++ b/crates/nu-cmd-base/src/hook.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::util::get_guaranteed_cwd; use miette::Result; use nu_engine::{eval_block, eval_block_with_early_return}; @@ -36,8 +38,7 @@ pub fn eval_env_change_hook( "env_change", )?; - engine_state - .previous_env_vars + Arc::make_mut(&mut engine_state.previous_env_vars) .insert(env_name.to_string(), after); } } diff --git a/crates/nu-cmd-extra/src/extra/filters/update_cells.rs b/crates/nu-cmd-extra/src/extra/filters/update_cells.rs index 4dbd9837c8..c488f1d7aa 100644 --- a/crates/nu-cmd-extra/src/extra/filters/update_cells.rs +++ b/crates/nu-cmd-extra/src/extra/filters/update_cells.rs @@ -7,6 +7,7 @@ use nu_protocol::{ PipelineIterator, ShellError, Signature, Span, SyntaxShape, Type, Value, }; use std::collections::HashSet; +use std::sync::Arc; #[derive(Clone)] pub struct UpdateCells; @@ -102,7 +103,7 @@ impl Command for UpdateCells { let metadata = input.metadata(); let ctrlc = engine_state.ctrlc.clone(); - let block: Block = engine_state.get_block(block.block_id).clone(); + let block: Arc = engine_state.get_block(block.block_id).clone(); let eval_block_fn = get_eval_block(&engine_state); let span = call.head; @@ -140,7 +141,7 @@ struct UpdateCellIterator { columns: Option>, engine_state: EngineState, stack: Stack, - block: Block, + block: Arc, eval_block_fn: EvalBlockFn, span: Span, } diff --git a/crates/nu-cmd-lang/src/example_support.rs b/crates/nu-cmd-lang/src/example_support.rs index 7010fc9a4e..8a654cab23 100644 --- a/crates/nu-cmd-lang/src/example_support.rs +++ b/crates/nu-cmd-lang/src/example_support.rs @@ -6,6 +6,7 @@ use nu_protocol::{ Example, PipelineData, Signature, Span, Type, Value, }; use std::collections::HashSet; +use std::sync::Arc; pub fn check_example_input_and_output_types_match_command_signature( example: &Example, @@ -76,7 +77,9 @@ fn eval_pipeline_without_terminal_expression( let (mut block, delta) = parse(src, engine_state); if block.pipelines.len() == 1 { let n_expressions = block.pipelines[0].elements.len(); - block.pipelines[0].elements.truncate(&n_expressions - 1); + Arc::make_mut(&mut block).pipelines[0] + .elements + .truncate(&n_expressions - 1); if !block.pipelines[0].elements.is_empty() { let empty_input = PipelineData::empty(); @@ -90,7 +93,7 @@ fn eval_pipeline_without_terminal_expression( } } -pub fn parse(contents: &str, engine_state: &EngineState) -> (Block, StateDelta) { +pub fn parse(contents: &str, engine_state: &EngineState) -> (Arc, StateDelta) { let mut working_set = StateWorkingSet::new(engine_state); let output = nu_parser::parse(&mut working_set, None, contents.as_bytes(), false); @@ -102,7 +105,7 @@ pub fn parse(contents: &str, engine_state: &EngineState) -> (Block, StateDelta) } pub fn eval_block( - block: Block, + block: Arc, input: PipelineData, cwd: &std::path::Path, engine_state: &mut Box, diff --git a/crates/nu-command/src/debug/ast.rs b/crates/nu-command/src/debug/ast.rs index f829cb972c..370f2f2445 100644 --- a/crates/nu-command/src/debug/ast.rs +++ b/crates/nu-command/src/debug/ast.rs @@ -53,9 +53,9 @@ impl Command for Ast { if to_json { // Get the block as json let serde_block_str = if minify { - serde_json::to_string(&block_output) + serde_json::to_string(&*block_output) } else { - serde_json::to_string_pretty(&block_output) + serde_json::to_string_pretty(&*block_output) }; let block_json = match serde_block_str { Ok(json) => json, diff --git a/crates/nu-command/src/debug/view_files.rs b/crates/nu-command/src/debug/view_files.rs index ad1c5c5edd..f9214f06a3 100644 --- a/crates/nu-command/src/debug/view_files.rs +++ b/crates/nu-command/src/debug/view_files.rs @@ -46,7 +46,7 @@ impl Command for ViewFiles { for (file, start, end) in engine_state.files() { records.push(Value::record( record! { - "filename" => Value::string(file, call.head), + "filename" => Value::string(&**file, call.head), "start" => Value::int(*start as i64, call.head), "end" => Value::int(*end as i64, call.head), "size" => Value::int(*end as i64 - *start as i64, call.head), diff --git a/crates/nu-command/src/formats/from/nuon.rs b/crates/nu-command/src/formats/from/nuon.rs index 249efcb842..b123c525ea 100644 --- a/crates/nu-command/src/formats/from/nuon.rs +++ b/crates/nu-command/src/formats/from/nuon.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use nu_protocol::ast::{Call, Expr, Expression, RecordItem}; use nu_protocol::engine::{Command, EngineState, Stack, StateWorkingSet}; use nu_protocol::{ @@ -97,7 +99,7 @@ impl Command for FromNuon { ty: Type::Nothing, } } else { - let mut pipeline = block.pipelines.remove(0); + let mut pipeline = Arc::make_mut(&mut block).pipelines.remove(0); if let Some(expr) = pipeline.elements.get(1) { return Err(ShellError::GenericError { diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index 0547d356d2..2834866919 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -18,6 +18,7 @@ use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; use std::process::{Command as CommandSys, Stdio}; use std::sync::mpsc; +use std::sync::Arc; use std::thread; #[derive(Clone)] @@ -442,7 +443,7 @@ impl ExternalCommand { let mut stack = stack.clone(); // Turn off color as we pass data through - engine_state.config.use_ansi_coloring = false; + Arc::make_mut(&mut engine_state.config).use_ansi_coloring = false; // Pipe input into the external command's stdin if let Some(mut stdin_write) = child.as_mut().stdin.take() { diff --git a/crates/nu-engine/src/env.rs b/crates/nu-engine/src/env.rs index 9e39ea2786..e927a86023 100644 --- a/crates/nu-engine/src/env.rs +++ b/crates/nu-engine/src/env.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use std::sync::Arc; use nu_protocol::ast::{Call, Expr}; use nu_protocol::engine::{EngineState, Stack, StateWorkingSet, PWD_ENV}; @@ -68,7 +69,8 @@ pub fn convert_env_values(engine_state: &mut EngineState, stack: &Stack) -> Opti } if let Ok(last_overlay_name) = &stack.last_overlay_name() { - if let Some(env_vars) = engine_state.env_vars.get_mut(last_overlay_name) { + if let Some(env_vars) = Arc::make_mut(&mut engine_state.env_vars).get_mut(last_overlay_name) + { for (k, v) in new_scope { env_vars.insert(k, v); } diff --git a/crates/nu-explore/src/nu_common/command.rs b/crates/nu-explore/src/nu_common/command.rs index adbcdb8874..e1a6e78774 100644 --- a/crates/nu-explore/src/nu_common/command.rs +++ b/crates/nu-explore/src/nu_common/command.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use nu_engine::eval_block; use nu_parser::parse; use nu_protocol::debugger::WithoutDebug; @@ -88,7 +90,8 @@ fn eval_source2( // // So we LITERALLY ignore all expressions except the LAST. if block.len() > 1 { - block.pipelines.drain(..block.pipelines.len() - 1); + let range = ..block.pipelines.len() - 1; + Arc::make_mut(&mut block).pipelines.drain(range); } let stack = &mut stack.push_redirection( diff --git a/crates/nu-lsp/src/lib.rs b/crates/nu-lsp/src/lib.rs index 70c49371c8..2b0e19c868 100644 --- a/crates/nu-lsp/src/lib.rs +++ b/crates/nu-lsp/src/lib.rs @@ -287,7 +287,7 @@ impl LanguageServer { for (file_path, file_start, file_end) in working_set.files() { if span.start >= *file_start && span.start < *file_end { return Some(GotoDefinitionResponse::Scalar(Location { - uri: Url::from_file_path(file_path).ok()?, + uri: Url::from_file_path(&**file_path).ok()?, range: Self::span_to_range(span, file, *file_start), })); } diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index cf53d7d53a..3aa133d177 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -18,8 +18,11 @@ use nu_protocol::{ span, Alias, BlockId, DeclId, Module, ModuleId, ParseError, PositionalArg, ResolvedImportPattern, Span, Spanned, SyntaxShape, Type, Value, VarId, }; -use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; pub const LIB_DIRS_VAR: &str = "NU_LIB_DIRS"; #[cfg(feature = "plugin")] @@ -1903,7 +1906,7 @@ fn parse_module_file( // Restore the currently parsed directory back working_set.currently_parsed_cwd = prev_currently_parsed_cwd; - let _ = working_set.add_block(block); + let _ = working_set.add_block(Arc::new(block)); let module_id = working_set.add_module(&module_name, module, module_comments); Some(module_id) @@ -2153,7 +2156,7 @@ pub fn parse_module( let (block, module, inner_comments) = parse_module_block(working_set, block_span, module_name.as_bytes()); - let block_id = working_set.add_block(block); + let block_id = working_set.add_block(Arc::new(block)); module_comments.extend(inner_comments); let module_id = working_set.add_module(&module_name, module, module_comments); @@ -2962,7 +2965,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline let output_type = rvalue_block.output_type(); - let block_id = working_set.add_block(rvalue_block); + let block_id = working_set.add_block(Arc::new(rvalue_block)); let rvalue = Expression { expr: Expr::Block(block_id), @@ -3219,7 +3222,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline let output_type = rvalue_block.output_type(); - let block_id = working_set.add_block(rvalue_block); + let block_id = working_set.add_block(Arc::new(rvalue_block)); let rvalue = Expression { expr: Expr::Block(block_id), @@ -3516,8 +3519,6 @@ pub fn parse_where(working_set: &mut StateWorkingSet, lite_command: &LiteCommand #[cfg(feature = "plugin")] pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline { - use std::sync::Arc; - use nu_plugin::{get_signature, PersistentPlugin, PluginDeclaration}; use nu_protocol::{ engine::Stack, IntoSpanned, PluginIdentity, PluginSignature, RegisteredPlugin, diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 71b66c4306..6fb5e67900 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -31,7 +31,10 @@ use crate::parse_keywords::{ use itertools::Itertools; use log::trace; -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; use std::{num::ParseIntError, str}; #[cfg(feature = "plugin")] @@ -2096,7 +2099,7 @@ pub fn parse_full_cell_path( let ty = output.output_type(); - let block_id = working_set.add_block(output); + let block_id = working_set.add_block(Arc::new(output)); tokens.next(); ( @@ -3146,7 +3149,7 @@ pub fn parse_row_condition(working_set: &mut StateWorkingSet, spans: &[Span]) -> default_value: None, }); - working_set.add_block(block) + working_set.add_block(Arc::new(block)) } }; @@ -4136,7 +4139,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> working_set.exit_scope(); - let block_id = working_set.add_block(output); + let block_id = working_set.add_block(Arc::new(output)); Expression { expr: Expr::Block(block_id), @@ -4477,7 +4480,7 @@ pub fn parse_closure_expression( working_set.exit_scope(); - let block_id = working_set.add_block(output); + let block_id = working_set.add_block(Arc::new(output)); Expression { expr: Expr::Closure(block_id), @@ -5177,7 +5180,7 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex let ty = output.ty.clone(); block.pipelines = vec![Pipeline::from_vec(vec![output])]; - let block_id = working_set.add_block(block); + let block_id = working_set.add_block(Arc::new(block)); let mut env_vars = vec![]; for sh in shorthand { @@ -6176,7 +6179,7 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) ..Default::default() }; - let block_id = working_set.add_block(block); + let block_id = working_set.add_block(Arc::new(block)); output.push(Argument::Positional(Expression { expr: Expr::Closure(block_id), @@ -6221,7 +6224,7 @@ pub fn parse( fname: Option<&str>, contents: &[u8], scoped: bool, -) -> Block { +) -> Arc { let name = match fname { Some(fname) => { // use the canonical name for this filename @@ -6246,7 +6249,7 @@ pub fn parse( working_set.error(err) } - parse_block(working_set, &output, new_span, scoped, false) + Arc::new(parse_block(working_set, &output, new_span, scoped, false)) } }; @@ -6261,7 +6264,10 @@ pub fn parse( &mut seen_blocks, &mut captures, ) { - Ok(_) => output.captures = captures.into_iter().map(|(var_id, _)| var_id).collect(), + Ok(_) => { + Arc::make_mut(&mut output).captures = + captures.into_iter().map(|(var_id, _)| var_id).collect(); + } Err(err) => working_set.error(err), } diff --git a/crates/nu-protocol/src/ast/expression.rs b/crates/nu-protocol/src/ast/expression.rs index 90a4a5aa42..d445b27872 100644 --- a/crates/nu-protocol/src/ast/expression.rs +++ b/crates/nu-protocol/src/ast/expression.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use serde::{Deserialize, Serialize}; use super::{Argument, Expr, ExternalArgument, RecordItem}; @@ -325,7 +327,7 @@ impl Expression { expr.replace_span(working_set, replaced, new_span); } Expr::Block(block_id) => { - let mut block = working_set.get_block(*block_id).clone(); + let mut block = (**working_set.get_block(*block_id)).clone(); for pipeline in block.pipelines.iter_mut() { for element in pipeline.elements.iter_mut() { @@ -333,10 +335,10 @@ impl Expression { } } - *block_id = working_set.add_block(block); + *block_id = working_set.add_block(Arc::new(block)); } Expr::Closure(block_id) => { - let mut block = working_set.get_block(*block_id).clone(); + let mut block = (**working_set.get_block(*block_id)).clone(); for pipeline in block.pipelines.iter_mut() { for element in pipeline.elements.iter_mut() { @@ -344,7 +346,7 @@ impl Expression { } } - *block_id = working_set.add_block(block); + *block_id = working_set.add_block(Arc::new(block)); } Expr::Binary(_) => {} Expr::Bool(_) => {} @@ -429,7 +431,7 @@ impl Expression { } } Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { - let mut block = working_set.get_block(*block_id).clone(); + let mut block = (**working_set.get_block(*block_id)).clone(); for pipeline in block.pipelines.iter_mut() { for element in pipeline.elements.iter_mut() { @@ -437,7 +439,7 @@ impl Expression { } } - *block_id = working_set.add_block(block); + *block_id = working_set.add_block(Arc::new(block)); } Expr::Table(headers, cells) => { for header in headers { diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index c20eac33fe..de713c3059 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -64,23 +64,29 @@ impl Clone for IsDebugging { /// will refer to the corresponding IDs rather than their definitions directly. At runtime, this means /// less copying and smaller structures. /// +/// Many of the larger objects in this structure are stored within `Arc` to decrease the cost of +/// cloning `EngineState`. While `Arc`s are generally immutable, they can be modified using +/// `Arc::make_mut`, which automatically clones to a new allocation if there are other copies of +/// the `Arc` already in use, but will let us modify the `Arc` directly if we have the only +/// reference to it. +/// /// Note that the runtime stack is not part of this global state. Runtime stacks are handled differently, /// but they also rely on using IDs rather than full definitions. #[derive(Clone)] pub struct EngineState { - files: Vec<(String, usize, usize)>, - file_contents: Vec<(Vec, usize, usize)>, + files: Vec<(Arc, usize, usize)>, + file_contents: Vec<(Arc>, usize, usize)>, pub(super) virtual_paths: Vec<(String, VirtualPath)>, vars: Vec, - decls: Vec>, - pub(super) blocks: Vec, - pub(super) modules: Vec, + decls: Arc>>, + pub(super) blocks: Vec>, + pub(super) modules: Vec>, usage: Usage, pub scope: ScopeFrame, pub ctrlc: Option>, - pub env_vars: EnvVars, - pub previous_env_vars: HashMap, - pub config: Config, + pub env_vars: Arc, + pub previous_env_vars: Arc>, + pub config: Arc, pub pipeline_externals_state: Arc<(AtomicU32, AtomicU32)>, pub repl_state: Arc>, pub table_decl_id: Option, @@ -122,9 +128,11 @@ impl EngineState { Variable::new(Span::new(0, 0), Type::Any, false), Variable::new(Span::new(0, 0), Type::Any, false), ], - decls: vec![], + decls: Arc::new(vec![]), blocks: vec![], - modules: vec![Module::new(DEFAULT_OVERLAY_NAME.as_bytes().to_vec())], + modules: vec![Arc::new(Module::new( + DEFAULT_OVERLAY_NAME.as_bytes().to_vec(), + ))], usage: Usage::new(), // make sure we have some default overlay: scope: ScopeFrame::with_empty_overlay( @@ -133,11 +141,13 @@ impl EngineState { false, ), ctrlc: None, - env_vars: [(DEFAULT_OVERLAY_NAME.to_string(), HashMap::new())] - .into_iter() - .collect(), - previous_env_vars: HashMap::new(), - config: Config::default(), + env_vars: Arc::new( + [(DEFAULT_OVERLAY_NAME.to_string(), HashMap::new())] + .into_iter() + .collect(), + ), + previous_env_vars: Arc::new(HashMap::new()), + config: Arc::new(Config::default()), pipeline_externals_state: Arc::new((AtomicU32::new(0), AtomicU32::new(0))), repl_state: Arc::new(Mutex::new(ReplState { buffer: "".to_string(), @@ -175,12 +185,16 @@ impl EngineState { self.files.extend(delta.files); self.file_contents.extend(delta.file_contents); self.virtual_paths.extend(delta.virtual_paths); - self.decls.extend(delta.decls); self.vars.extend(delta.vars); self.blocks.extend(delta.blocks); self.modules.extend(delta.modules); self.usage.merge_with(delta.usage); + // Avoid potentially cloning the Arc if we aren't adding anything + if !delta.decls.is_empty() { + Arc::make_mut(&mut self.decls).extend(delta.decls); + } + let first = delta.scope.remove(0); for (delta_name, delta_overlay) in first.clone().overlays { @@ -268,7 +282,7 @@ impl EngineState { for mut scope in stack.env_vars.drain(..) { for (overlay_name, mut env) in scope.drain() { - if let Some(env_vars) = self.env_vars.get_mut(&overlay_name) { + if let Some(env_vars) = Arc::make_mut(&mut self.env_vars).get_mut(&overlay_name) { // Updating existing overlay for (k, v) in env.drain() { if k == "config" { @@ -276,7 +290,7 @@ impl EngineState { // Instead, mutate a clone of it with into_config(), and put THAT in env_vars. let mut new_record = v.clone(); let (config, error) = new_record.into_config(&self.config); - self.config = config; + self.config = Arc::new(config); config_updated = true; env_vars.insert(k, new_record); if let Some(e) = error { @@ -288,7 +302,7 @@ impl EngineState { } } else { // Pushing a new overlay - self.env_vars.insert(overlay_name, env); + Arc::make_mut(&mut self.env_vars).insert(overlay_name, env); } } } @@ -422,10 +436,10 @@ impl EngineState { pub fn add_env_var(&mut self, name: String, val: Value) { let overlay_name = String::from_utf8_lossy(self.last_overlay_name(&[])).to_string(); - if let Some(env_vars) = self.env_vars.get_mut(&overlay_name) { + if let Some(env_vars) = Arc::make_mut(&mut self.env_vars).get_mut(&overlay_name) { env_vars.insert(name, val); } else { - self.env_vars + Arc::make_mut(&mut self.env_vars) .insert(overlay_name, [(name, val)].into_iter().collect()); } } @@ -752,7 +766,7 @@ impl EngineState { self.update_plugin_gc_configs(&conf.plugin_gc); } - self.config = conf; + self.config = Arc::new(conf); } /// Fetch the configuration for a plugin @@ -867,7 +881,7 @@ impl EngineState { .collect() } - pub fn get_block(&self, block_id: BlockId) -> &Block { + pub fn get_block(&self, block_id: BlockId) -> &Arc { self.blocks .get(block_id) .expect("internal error: missing block") @@ -878,7 +892,7 @@ impl EngineState { /// Prefer to use [`.get_block()`] in most cases - `BlockId`s that don't exist are normally a /// compiler error. This only exists to stop plugins from crashing the engine if they send us /// something invalid. - pub fn try_get_block(&self, block_id: BlockId) -> Option<&Block> { + pub fn try_get_block(&self, block_id: BlockId) -> Option<&Arc> { self.blocks.get(block_id) } @@ -902,7 +916,7 @@ impl EngineState { } } - pub fn files(&self) -> impl Iterator { + pub fn files(&self) -> impl Iterator, usize, usize)> { self.files.iter() } @@ -911,9 +925,10 @@ impl EngineState { let next_span_end = next_span_start + contents.len(); self.file_contents - .push((contents, next_span_start, next_span_end)); + .push((Arc::new(contents), next_span_start, next_span_end)); - self.files.push((filename, next_span_start, next_span_end)); + self.files + .push((Arc::new(filename), next_span_start, next_span_end)); self.num_files() - 1 } @@ -953,7 +968,7 @@ impl EngineState { .unwrap_or_default() } - pub fn get_file_contents(&self) -> &[(Vec, usize, usize)] { + pub fn get_file_contents(&self) -> &[(Arc>, usize, usize)] { &self.file_contents } @@ -1051,8 +1066,8 @@ mod engine_state_tests { engine_state.merge_delta(delta)?; assert_eq!(engine_state.num_files(), 2); - assert_eq!(&engine_state.files[0].0, "test.nu"); - assert_eq!(&engine_state.files[1].0, "child.nu"); + assert_eq!(&*engine_state.files[0].0, "test.nu"); + assert_eq!(&*engine_state.files[1].0, "child.nu"); Ok(()) } diff --git a/crates/nu-protocol/src/engine/state_delta.rs b/crates/nu-protocol/src/engine/state_delta.rs index cb53a87db8..d12090b6c2 100644 --- a/crates/nu-protocol/src/engine/state_delta.rs +++ b/crates/nu-protocol/src/engine/state_delta.rs @@ -12,13 +12,13 @@ use crate::RegisteredPlugin; /// can be applied to the global state to update it to contain both previous state and the state held /// within the delta. pub struct StateDelta { - pub(super) files: Vec<(String, usize, usize)>, - pub(crate) file_contents: Vec<(Vec, usize, usize)>, + pub(super) files: Vec<(Arc, usize, usize)>, + pub(crate) file_contents: Vec<(Arc>, usize, usize)>, pub(super) virtual_paths: Vec<(String, VirtualPath)>, pub(super) vars: Vec, // indexed by VarId pub(super) decls: Vec>, // indexed by DeclId - pub blocks: Vec, // indexed by BlockId - pub(super) modules: Vec, // indexed by ModuleId + pub blocks: Vec>, // indexed by BlockId + pub(super) modules: Vec>, // indexed by ModuleId pub(super) usage: Usage, pub scope: Vec, #[cfg(feature = "plugin")] @@ -131,7 +131,7 @@ impl StateDelta { self.scope.pop(); } - pub fn get_file_contents(&self) -> &[(Vec, usize, usize)] { + pub fn get_file_contents(&self) -> &[(Arc>, usize, usize)] { &self.file_contents } } diff --git a/crates/nu-protocol/src/engine/state_working_set.rs b/crates/nu-protocol/src/engine/state_working_set.rs index 58cec0e015..2e0811963c 100644 --- a/crates/nu-protocol/src/engine/state_working_set.rs +++ b/crates/nu-protocol/src/engine/state_working_set.rs @@ -254,7 +254,7 @@ impl<'a> StateWorkingSet<'a> { } } - pub fn add_block(&mut self, block: Block) -> BlockId { + pub fn add_block(&mut self, block: Arc) -> BlockId { self.delta.blocks.push(block); self.num_blocks() - 1 @@ -263,7 +263,7 @@ impl<'a> StateWorkingSet<'a> { pub fn add_module(&mut self, name: &str, module: Module, comments: Vec) -> ModuleId { let name = name.as_bytes().to_vec(); - self.delta.modules.push(module); + self.delta.modules.push(Arc::new(module)); let module_id = self.num_modules() - 1; if !comments.is_empty() { @@ -296,7 +296,7 @@ impl<'a> StateWorkingSet<'a> { self.permanent_state.next_span_start() } - pub fn files(&'a self) -> impl Iterator { + pub fn files(&'a self) -> impl Iterator, usize, usize)> { self.permanent_state.files().chain(self.delta.files.iter()) } @@ -320,7 +320,7 @@ impl<'a> StateWorkingSet<'a> { pub fn add_file(&mut self, filename: String, contents: &[u8]) -> FileId { // First, look for the file to see if we already have it for (idx, (fname, file_start, file_end)) in self.files().enumerate() { - if fname == &filename { + if **fname == filename { let prev_contents = self.get_span_contents(Span::new(*file_start, *file_end)); if prev_contents == contents { return idx; @@ -331,13 +331,15 @@ impl<'a> StateWorkingSet<'a> { let next_span_start = self.next_span_start(); let next_span_end = next_span_start + contents.len(); - self.delta - .file_contents - .push((contents.to_vec(), next_span_start, next_span_end)); + self.delta.file_contents.push(( + Arc::new(contents.to_vec()), + next_span_start, + next_span_end, + )); self.delta .files - .push((filename, next_span_start, next_span_end)); + .push((Arc::new(filename), next_span_start, next_span_end)); self.num_files() - 1 } @@ -353,7 +355,7 @@ impl<'a> StateWorkingSet<'a> { let (file_id, ..) = self .files() .enumerate() - .find(|(_, (fname, _, _))| fname == filename)?; + .find(|(_, (fname, _, _))| **fname == filename)?; Some(self.get_span_for_file(file_id)) } @@ -626,8 +628,8 @@ impl<'a> StateWorkingSet<'a> { pub fn list_env(&self) -> Vec { let mut env_vars = vec![]; - for env_var in self.permanent_state.env_vars.clone().into_iter() { - env_vars.push(env_var.0) + for env_var in self.permanent_state.env_vars.iter() { + env_vars.push(env_var.0.clone()); } env_vars @@ -742,7 +744,7 @@ impl<'a> StateWorkingSet<'a> { output } - pub fn get_block(&self, block_id: BlockId) -> &Block { + pub fn get_block(&self, block_id: BlockId) -> &Arc { let num_permanent_blocks = self.permanent_state.num_blocks(); if block_id < num_permanent_blocks { self.permanent_state.get_block(block_id) @@ -774,6 +776,7 @@ impl<'a> StateWorkingSet<'a> { self.delta .blocks .get_mut(block_id - num_permanent_blocks) + .map(Arc::make_mut) .expect("internal error: missing block") } } @@ -957,7 +960,7 @@ impl<'a> StateWorkingSet<'a> { build_usage(&comment_lines) } - pub fn find_block_by_span(&self, span: Span) -> Option { + pub fn find_block_by_span(&self, span: Span) -> Option> { for block in &self.delta.blocks { if Some(span) == block.span { return Some(block.clone()); @@ -1063,7 +1066,7 @@ impl<'a> miette::SourceCode for &StateWorkingSet<'a> { } let data = span_contents.data(); - if filename == "" { + if **filename == "" { if debugging { let success_cli = "Successfully read CLI span"; dbg!(success_cli, String::from_utf8_lossy(data)); @@ -1081,7 +1084,7 @@ impl<'a> miette::SourceCode for &StateWorkingSet<'a> { dbg!(success_file); } return Ok(Box::new(miette::MietteSpanContents::new_named( - filename.clone(), + (**filename).clone(), data, retranslated, span_contents.line(), diff --git a/src/config_files.rs b/src/config_files.rs index 9b6db0293d..d2ccf87d50 100644 --- a/src/config_files.rs +++ b/src/config_files.rs @@ -11,6 +11,7 @@ use std::fs::File; use std::io::Write; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::Path; +use std::sync::Arc; pub(crate) const NUSHELL_FOLDER: &str = "nushell"; const CONFIG_FILE: &str = "config.nu"; @@ -210,7 +211,7 @@ pub(crate) fn setup_config( eprintln!( "A panic occurred while reading configuration files, using default configuration." ); - engine_state.config = Config::default() + engine_state.config = Arc::new(Config::default()) } } diff --git a/src/ide.rs b/src/ide.rs index f59011d477..59422c3ddc 100644 --- a/src/ide.rs +++ b/src/ide.rs @@ -165,7 +165,7 @@ pub fn goto_def(engine_state: &mut EngineState, file_path: &str, location: &Valu "{}", json!( { - "file": file.0, + "file": &**file.0, "start": span.start - file.1, "end": span.end - file.1 } @@ -185,7 +185,7 @@ pub fn goto_def(engine_state: &mut EngineState, file_path: &str, location: &Valu "{}", json!( { - "file": file.0, + "file": &**file.0, "start": var.declaration_span.start - file.1, "end": var.declaration_span.end - file.1 }