Skip to main content

routers_trellis/
solved.rs

1use crate::{LayerId, Path, Solve, SolveError, Trellis, TrellisError};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6/// A solved trellis: a [`Trellis`] paired with the minimum-cost [`Path`]
7/// through it.
8///
9/// `Solved` is a certificate, not a cache — the only way to construct one is
10/// [`Trellis::solve`], and the trellis inside is immutable, so holding a
11/// `Solved` guarantees its path describes its trellis. Leaving is consuming:
12/// [`append`](Self::append) to grow it, [`reopen`](Self::reopen) to mutate it.
13#[derive(Clone, Debug)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub struct Solved {
16    trellis: Trellis,
17    path: Path,
18}
19
20impl Solved {
21    /// The minimum-cost path through the trellis.
22    pub fn path(&self) -> &Path {
23        &self.path
24    }
25
26    /// The path's total cost.
27    pub fn cost(&self) -> u32 {
28        self.path.cost
29    }
30
31    /// The solved trellis, read-only.
32    pub fn trellis(&self) -> &Trellis {
33        &self.trellis
34    }
35
36    /// Grow by one layer, returning to the building state with the new
37    /// layer's id. The path is discarded — it no longer spans every layer.
38    /// A rejected width hands the certificate back untouched.
39    // Handing the caller's state back on failure is the point; its size is theirs.
40    #[allow(clippy::result_large_err)]
41    pub fn append(mut self, width: u32) -> Result<(Trellis, LayerId), (Solved, TrellisError)> {
42        match self.trellis.add_layer(width) {
43            Ok(id) => Ok((self.trellis, id)),
44            Err(e) => Err((self, e)),
45        }
46    }
47
48    /// Return to the building state for surgery or windowing, discarding
49    /// the path.
50    pub fn reopen(self) -> Trellis {
51        self.trellis
52    }
53}
54
55impl Trellis {
56    /// Solve this trellis into a [`Solved`] certificate; a failed solve hands
57    /// the trellis back alongside the error.
58    pub fn solve<S: Solve>(self, solver: &S) -> Result<Solved, (Trellis, SolveError)> {
59        match solver.solve(&self) {
60            Ok(path) => Ok(Solved {
61                trellis: self,
62                path,
63            }),
64            Err(e) => Err((self, e)),
65        }
66    }
67}