deterministic id generator per module (#5811)

* deterministic id generator per module

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* non

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* do not remake the planes if they are alreaady made;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* do not remake the planes if they are alreaady made;

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* clippy

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2025-03-15 10:08:39 -07:00
committed by GitHub
parent 9c986d3aa8
commit 3f02bb2065
86 changed files with 955 additions and 918 deletions

View File

@ -10,7 +10,9 @@ use uuid::Uuid;
use crate::{
errors::{KclError, KclErrorDetails, Severity},
execution::{
annotations, kcl_value,
annotations,
id_generator::IdGenerator,
kcl_value,
memory::{ProgramMemory, Stack},
Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue,
Operation, UnitAngle, UnitLen,
@ -26,12 +28,11 @@ use crate::{
pub struct ExecState {
pub(super) global: GlobalState,
pub(super) mod_local: ModuleState,
pub(super) exec_context: Option<super::ExecutorContext>,
}
#[derive(Debug, Clone)]
pub(super) struct GlobalState {
/// The stable artifact ID generator.
pub id_generator: IdGenerator,
/// Map from source file absolute path to module ID.
pub path_to_source_id: IndexMap<ModulePath, ModuleId>,
/// Map from module ID to source file.
@ -62,6 +63,8 @@ pub(super) struct GlobalState {
#[derive(Debug, Clone)]
pub(super) struct ModuleState {
/// The id generator for this module.
pub id_generator: IdGenerator,
pub stack: Stack,
/// The current value of the pipe operator returned from the previous
/// expression. If we're not currently in a pipeline, this will be None.
@ -73,25 +76,21 @@ pub(super) struct ModuleState {
}
impl ExecState {
pub fn new(exec_settings: &ExecutorSettings) -> Self {
pub fn new(exec_context: &super::ExecutorContext) -> Self {
ExecState {
global: GlobalState::new(exec_settings),
mod_local: ModuleState::new(exec_settings, None, ProgramMemory::new()),
global: GlobalState::new(&exec_context.settings),
mod_local: ModuleState::new(&exec_context.settings, None, ProgramMemory::new(), Default::default()),
exec_context: Some(exec_context.clone()),
}
}
pub(super) fn reset(&mut self, exec_settings: &ExecutorSettings) {
let mut id_generator = self.global.id_generator.clone();
// We do not pop the ids, since we want to keep the same id generator.
// This is for the front end to keep track of the ids.
id_generator.next_id = 0;
let mut global = GlobalState::new(exec_settings);
global.id_generator = id_generator;
pub(super) fn reset(&mut self, exec_context: &super::ExecutorContext) {
let global = GlobalState::new(&exec_context.settings);
*self = ExecState {
global,
mod_local: ModuleState::new(exec_settings, None, ProgramMemory::new()),
mod_local: ModuleState::new(&exec_context.settings, None, ProgramMemory::new(), Default::default()),
exec_context: Some(exec_context.clone()),
};
}
@ -113,7 +112,7 @@ impl ExecState {
/// Convert to execution outcome when running in WebAssembly. We want to
/// reduce the amount of data that crosses the WASM boundary as much as
/// possible.
pub fn to_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
pub async fn to_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
// Fields are opt-in so that we don't accidentally leak private internal
// state when we add more to ExecState.
ExecOutcome {
@ -132,10 +131,15 @@ impl ExecState {
.iter()
.map(|(k, v)| ((*v), k.clone()))
.collect(),
default_planes: if let Some(ctx) = &self.exec_context {
ctx.engine.get_default_planes().read().await.clone()
} else {
None
},
}
}
pub fn to_mock_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
pub async fn to_mock_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
// Fields are opt-in so that we don't accidentally leak private internal
// state when we add more to ExecState.
ExecOutcome {
@ -149,6 +153,11 @@ impl ExecState {
artifact_graph: Default::default(),
errors: self.global.errors,
filenames: Default::default(),
default_planes: if let Some(ctx) = &self.exec_context {
ctx.engine.get_default_planes().read().await.clone()
} else {
None
},
}
}
@ -160,8 +169,12 @@ impl ExecState {
&mut self.mod_local.stack
}
pub(crate) fn next_uuid(&mut self) -> Uuid {
self.global.id_generator.next_uuid()
pub fn next_uuid(&mut self) -> Uuid {
self.mod_local.id_generator.next_uuid()
}
pub fn id_generator(&mut self) -> &mut IdGenerator {
&mut self.mod_local.id_generator
}
pub(crate) fn add_artifact(&mut self, artifact: Artifact) {
@ -241,7 +254,6 @@ impl ExecState {
impl GlobalState {
fn new(settings: &ExecutorSettings) -> Self {
let mut global = GlobalState {
id_generator: Default::default(),
path_to_source_id: Default::default(),
module_infos: Default::default(),
artifacts: Default::default(),
@ -274,8 +286,14 @@ impl GlobalState {
}
impl ModuleState {
pub(super) fn new(exec_settings: &ExecutorSettings, std_path: Option<String>, memory: Arc<ProgramMemory>) -> Self {
pub(super) fn new(
exec_settings: &ExecutorSettings,
std_path: Option<String>,
memory: Arc<ProgramMemory>,
module_id: Option<ModuleId>,
) -> Self {
ModuleState {
id_generator: IdGenerator::new(module_id),
stack: memory.new_stack(),
pipe_value: Default::default(),
module_exports: Default::default(),
@ -332,29 +350,3 @@ impl MetaSettings {
Ok(())
}
}
/// A generator for ArtifactIds that can be stable across executions.
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct IdGenerator {
pub(super) next_id: usize,
ids: Vec<uuid::Uuid>,
}
impl IdGenerator {
pub fn new() -> Self {
Self::default()
}
pub fn next_uuid(&mut self) -> uuid::Uuid {
if let Some(id) = self.ids.get(self.next_id) {
self.next_id += 1;
*id
} else {
let id = uuid::Uuid::new_v4();
self.ids.push(id);
self.next_id += 1;
id
}
}
}