presolve_compiler/
state_projection.rs1use serde::Serialize;
4
5use crate::{resume_value_codec, StateInstanceStorageRegistry};
6
7pub const STATE_PROJECTION_SCHEMA_VERSION: u32 = 1;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
10#[serde(rename_all = "snake_case")]
11pub enum StateResumeAdmissionV1 {
12 CodecBacked,
13 Rejected,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
17#[serde(rename_all = "snake_case")]
18pub enum StateUpdateCoverageV1 {
19 ExistingLowering,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
23pub struct StateProjectionRecordV1 {
24 pub instance_slot: String,
25 pub component_instance: String,
26 pub state: String,
27 pub storage: String,
28 pub semantic_type: String,
29 pub resume_admission: StateResumeAdmissionV1,
30 pub update_coverage: StateUpdateCoverageV1,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
34pub struct StateProjectionV1 {
35 pub schema_version: u32,
36 pub records: Vec<StateProjectionRecordV1>,
37}
38
39#[must_use]
40pub fn build_state_projection_v1(registry: &StateInstanceStorageRegistry) -> StateProjectionV1 {
41 let mut records = registry
42 .records
43 .iter()
44 .map(|record| StateProjectionRecordV1 {
45 instance_slot: record.slot_id.to_string(),
46 component_instance: record.component_instance_id.as_str().to_owned(),
47 state: record.state_id.as_str().to_owned(),
48 storage: record.storage_id.as_str().to_owned(),
49 semantic_type: crate::semantic_type_text(&record.semantic_type),
50 resume_admission: if resume_value_codec(&record.semantic_type).is_ok() {
51 StateResumeAdmissionV1::CodecBacked
52 } else {
53 StateResumeAdmissionV1::Rejected
54 },
55 update_coverage: StateUpdateCoverageV1::ExistingLowering,
56 })
57 .collect::<Vec<_>>();
58 records.sort_by(|left, right| left.instance_slot.cmp(&right.instance_slot));
59 StateProjectionV1 {
60 schema_version: STATE_PROJECTION_SCHEMA_VERSION,
61 records,
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 #[test]
69 fn preserves_instance_qualified_state_identity_and_codec_admission() {
70 let model = crate::build_application_semantic_model(&presolve_parser::parse_file(
71 "src/App.tsx",
72 r#"@component("x-app") class App { count = state(0); render() { return <p>{this.count}</p>; } }"#,
73 ));
74 let registry = crate::build_state_instance_storage_registry(
75 &model,
76 &crate::lower_components_to_ir(&model),
77 );
78 let projection = build_state_projection_v1(®istry);
79 assert_eq!(projection.schema_version, STATE_PROJECTION_SCHEMA_VERSION);
80 assert_eq!(
81 projection.records[0].resume_admission,
82 StateResumeAdmissionV1::CodecBacked
83 );
84 }
85}