Skip to content

Migrate models to validated deserialization via serde(try_from) #704

@isPANN

Description

@isPANN

Problem

Most model structs (~55) use #[derive(Deserialize)] which bypasses constructor validation (assert!/panic! in new()). When users load invalid JSON via pred solve/pred evaluate/pred reduce/pred inspect, the deserialization path (serde_json::from_value in declare_variants! factory) skips all checks, leading to:

  • Runtime panics with unhelpful messages (e.g., index out of bounds in SpinGlass when fields.len() != num_spins)
  • Silent invalid state (e.g., ExactCoverBy3Sets with universe_size % 3 != 0 — silently unsolvable)

pred create is safe (constructs via new()). Only the JSON loading path is affected.

Already protected (~8 models)

Models with manual impl Deserialize, serde(from), or serde(try_from):

  • SequencingWithinIntervals, SequencingToMinimizeMaximumCumulativeCost, RectilinearPictureCompression, PartiallyOrderedKnapsack, SumOfSquaresPartition, MultipleChoiceBranching, StrongConnectivityAugmentation, BalancedCompleteBipartiteSubgraph

Proposed fix: #[serde(try_from)]

Replace #[derive(Deserialize)] with #[serde(try_from = "RawStruct")] + impl TryFrom:

#[derive(Serialize, Deserialize)]
#[serde(try_from = "FooRaw")]
pub struct Foo { ... }

#[derive(Deserialize)]
struct FooRaw { /* same fields */ }

impl TryFrom<FooRaw> for Foo {
    type Error = String;
    fn try_from(raw: FooRaw) -> Result<Self, String> {
        // reuse validation logic from new(), return Result instead of panic
    }
}

Advantages over manual impl Deserialize:

  • No hand-written Deserializer trait code
  • Validation errors become proper serde errors (clean CLI messages)
  • Shared validation function between new() (unwrap/panic) and TryFrom (propagate)

Scope

~55 models need migration. Can be done incrementally per-category (graph/, misc/, set/, algebraic/, formula/).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestlow prioritywait, wait, wait, do I really need this?

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions