Entropyk/_bmad-output/implementation-artifacts/9-8-systemstate-dedicated-struct.md

5.5 KiB

Story 9.8: SystemState Dedicated Struct

Status: ready-for-dev

Story

As a Rust developer, I want a dedicated SystemState struct instead of a type alias, so that I have layout validation, typed access methods, and better semantics for the solver state.

Acceptance Criteria

  1. Given SystemState is currently Vec<f64> in crates/components/src/lib.rs:182 When the struct is created Then pressure(edge_idx) returns Pressure type And enthalpy(edge_idx) returns Enthalpy type And set_pressure() and set_enthalpy() accept typed physical quantities

  2. Given a SystemState instance When accessing data Then AsRef<[f64]> and AsMut<[f64]> are implemented for solver compatibility And From<Vec<f64>> and From<SystemState> for Vec<f64> enable migration

  3. Given invalid data (odd length vector) When calling SystemState::from_vec() Then panic with clear error message

  4. Given out-of-bounds edge index When calling pressure() or enthalpy() Then returns None (safe, no panic)

  5. Given all tests passing before change When refactoring is complete Then cargo test --workspace passes And public API is unchanged for solver consumers

Tasks / Subtasks

  • Task 1: Create SystemState struct in entropyk_core (AC: 1, 3, 4)

    • Create crates/core/src/state.rs with SystemState struct
    • Implement new(edge_count), from_vec(), edge_count()
    • Implement pressure(), enthalpy() returning Option<Pressure/Enthalpy>
    • Implement set_pressure(), set_enthalpy() accepting typed values
    • Implement as_slice(), as_mut_slice(), into_vec()
    • Implement iter_edges() iterator
  • Task 2: Implement trait compatibility (AC: 2)

    • Implement AsRef<[f64]> for solver compatibility
    • Implement AsMut<[f64]> for mutable access
    • Implement From<Vec<f64>> and From<SystemState> for Vec<f64>
    • Implement Default trait
  • Task 3: Export from entropyk_core (AC: 5)

    • Add state module to crates/core/src/lib.rs
    • Export SystemState from crate root
  • Task 4: Migrate from type alias (AC: 5)

    • Remove pub type SystemState = Vec<f64>; from crates/components/src/lib.rs
    • Add use entropyk_core::SystemState; to components crate
    • Update solver crate imports if needed
  • Task 5: Add unit tests (AC: 3, 4)

    • Test new() creates correct size
    • Test pressure()/enthalpy() accessors
    • Test out-of-bounds returns None
    • Test from_vec() with valid and invalid data
    • Test iter_edges() iteration
    • Test From/Into conversions
  • Task 6: Add documentation (AC: 5)

    • Add rustdoc for struct and all public methods
    • Document layout: [P_edge0, h_edge0, P_edge1, h_edge1, ...]
    • Add inline code examples

Dev Notes

Current Implementation

// crates/components/src/lib.rs:182
pub type SystemState = Vec<f64>;

Layout: Each edge in the system graph has 2 variables: [P0, h0, P1, h1, ...]

  • P: Pressure in Pascals
  • h: Enthalpy in J/kg

Proposed Implementation

// crates/core/src/state.rs

pub struct SystemState {
    data: Vec<f64>,
    edge_count: usize,
}

impl SystemState {
    pub fn new(edge_count: usize) -> Self;
    pub fn from_vec(data: Vec<f64>) -> Self;  // panics on odd length
    pub fn edge_count(&self) -> usize;
    
    pub fn pressure(&self, edge_idx: usize) -> Option<Pressure>;
    pub fn enthalpy(&self, edge_idx: usize) -> Option<Enthalpy>;
    pub fn set_pressure(&mut self, edge_idx: usize, p: Pressure);
    pub fn set_enthalpy(&mut self, edge_idx: usize, h: Enthalpy);
    
    pub fn as_slice(&self) -> &[f64];
    pub fn as_mut_slice(&mut self) -> &mut [f64];
    pub fn into_vec(self) -> Vec<f64>;
    pub fn iter_edges(&self) -> impl Iterator<Item = (Pressure, Enthalpy)> + '_;
}

Architecture Compliance

  • NewType Pattern: Consistent with architecture requirement for type-safe physical quantities
  • Zero-Allocation in Hot Path: Internal Vec<f64> is pre-allocated; no allocation in accessors
  • Error Handling: Out-of-bounds returns Option::None, not panic (except from_vec with odd length)

Files to Touch

File Action
crates/core/src/state.rs Create
crates/core/src/lib.rs Add pub mod state; and re-export
crates/components/src/lib.rs Remove type alias, add import from core
crates/solver/src/*.rs Update imports if needed (may work via re-export)

Project Structure Notes

  • SystemState belongs in entropyk_core (shared between solver and components)
  • Physical types (Pressure, Enthalpy) already exist in entropyk_core
  • Solver uses AsRef<[f64]> trait - no breaking change

Testing Standards

  • Use approx crate for float comparisons
  • Tolerance: 1e-9 for exact values (matches NFR determinism requirement)
  • Run cargo test --workspace to verify no regressions

References

  • [Source: architecture.md#Core-Architectural-Decisions] - NewType pattern requirement
  • [Source: epics.md#Story-9.8] - Story definition
  • [Source: crates/components/src/lib.rs:182] - Current type alias location

Dev Agent Record

Agent Model Used

(To be filled during implementation)

Debug Log References

(To be filled during implementation)

Completion Notes List

(To be filled during implementation)

File List

(To be filled during implementation)