Rewrite SpecifiedValue
as a read-only structure
This commit is contained in:
parent
8b4a72c60c
commit
84bfdefccb
4 changed files with 41 additions and 44 deletions
|
@ -13,6 +13,7 @@ itertools = "0.13.0"
|
|||
js-sys = "0.3.70"
|
||||
lazy_static = "1.5.0"
|
||||
nalgebra = "0.33.0"
|
||||
readonly = "0.2.12"
|
||||
rustc-hash = "2.0.0"
|
||||
slab = "0.4.9"
|
||||
sycamore = "0.9.0-beta.3"
|
||||
|
|
|
@ -7,7 +7,7 @@ use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
|
|||
|
||||
use crate::{
|
||||
engine::{Q, local_unif_to_std, realize_gram, ConfigSubspace, PartialMatrix},
|
||||
specified::{SpecifiedValue, SpecifiedValue::{Absent, Present}}
|
||||
specified::SpecifiedValue
|
||||
};
|
||||
|
||||
// the types of the keys we use to access an assembly's elements and regulators
|
||||
|
@ -239,7 +239,7 @@ impl Assembly {
|
|||
reps.0.dot(&(&*Q * reps.1))
|
||||
}
|
||||
);
|
||||
let set_point = create_signal(Absent);
|
||||
let set_point = create_signal(SpecifiedValue::from_empty_spec());
|
||||
self.insert_regulator(Regulator {
|
||||
subjects: subjects,
|
||||
measurement: measurement,
|
||||
|
@ -256,9 +256,9 @@ impl Assembly {
|
|||
&JsValue::from(reg.subjects.0),
|
||||
&JsValue::from(reg.subjects.1),
|
||||
&JsValue::from(":"),
|
||||
&JsValue::from(reg.set_point.with_untracked(
|
||||
|set_pt| set_pt.spec()
|
||||
))
|
||||
®.set_point.with_untracked(
|
||||
|set_pt| JsValue::from(set_pt.spec.as_str())
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -269,7 +269,7 @@ impl Assembly {
|
|||
console::log_1(&JsValue::from(
|
||||
format!("Updated constraint with subjects ({}, {})", subjects.0, subjects.1)
|
||||
));
|
||||
if set_point.with(|set_pt| matches!(set_pt, Present { .. })) {
|
||||
if set_point.with(|set_pt| set_pt.is_present()) {
|
||||
self.realize();
|
||||
}
|
||||
});
|
||||
|
@ -292,11 +292,11 @@ impl Assembly {
|
|||
self.regulators.with_untracked(|regs| {
|
||||
for (_, reg) in regs {
|
||||
reg.set_point.with_untracked(|set_pt| {
|
||||
if let Present { value, .. } = set_pt {
|
||||
if let Some(val) = set_pt.value {
|
||||
let subjects = reg.subjects;
|
||||
let row = elts[subjects.0].column_index.unwrap();
|
||||
let col = elts[subjects.1].column_index.unwrap();
|
||||
gram_to_be.push_sym(row, col, *value);
|
||||
gram_to_be.push_sym(row, col, val);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
Regulator,
|
||||
RegulatorKey
|
||||
},
|
||||
specified::{SpecifiedValue, SpecifiedValue::{Absent, Present}}
|
||||
specified::SpecifiedValue
|
||||
};
|
||||
|
||||
// an editable view of a regulator
|
||||
|
@ -22,7 +22,7 @@ use crate::{
|
|||
fn RegulatorInput(regulator: Regulator) -> View {
|
||||
let valid = create_signal(true);
|
||||
let value = create_signal(
|
||||
regulator.set_point.with_untracked(|set_pt| set_pt.spec())
|
||||
regulator.set_point.with_untracked(|set_pt| set_pt.spec.clone())
|
||||
);
|
||||
|
||||
// this closure resets the input value to the regulator's set point
|
||||
|
@ -30,7 +30,7 @@ fn RegulatorInput(regulator: Regulator) -> View {
|
|||
let reset_value = move || {
|
||||
batch(|| {
|
||||
valid.set(true);
|
||||
value.set(regulator.set_point.with(|set_pt| set_pt.spec()));
|
||||
value.set(regulator.set_point.with(|set_pt| set_pt.spec.clone()));
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -44,9 +44,10 @@ fn RegulatorInput(regulator: Regulator) -> View {
|
|||
class=move || {
|
||||
if valid.get() {
|
||||
regulator.set_point.with(|set_pt| {
|
||||
match set_pt {
|
||||
Absent => "regulator-input",
|
||||
Present { .. } => "regulator-input constraint"
|
||||
if set_pt.is_present() {
|
||||
"regulator-input constraint"
|
||||
} else {
|
||||
"regulator-input"
|
||||
}
|
||||
})
|
||||
} else {
|
||||
|
|
|
@ -1,48 +1,43 @@
|
|||
use std::num::ParseFloatError;
|
||||
|
||||
// to construct a `SpecifiedValue` that might be `Present`, use the associated
|
||||
// function `try_from`. this ensures that `spec` is always a valid specification
|
||||
// of `value` according to the format discussed at the implementation of
|
||||
// `TryFrom<String>`
|
||||
pub enum SpecifiedValue {
|
||||
Absent,
|
||||
Present {
|
||||
spec: String,
|
||||
value: f64
|
||||
// a real number described by a specification string. since the structure is
|
||||
// read-only, we can guarantee that `spec` always specifies `value` in the
|
||||
// following format
|
||||
// ┌──────────────────────────────────────────────────────┬───────────┐
|
||||
// │ `spec` │ `value` │
|
||||
// ┝━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━┥
|
||||
// │ a string that parses to the floating-point value `x` │ `Some(x)` │
|
||||
// ├──────────────────────────────────────────────────────┼───────────┤
|
||||
// │ the empty string │ `None` │
|
||||
// └──────────────────────────────────────────────────────┴───────────┘
|
||||
#[readonly::make]
|
||||
pub struct SpecifiedValue {
|
||||
pub spec: String,
|
||||
pub value: Option<f64>
|
||||
}
|
||||
}
|
||||
|
||||
use SpecifiedValue::{Absent, Present};
|
||||
|
||||
impl SpecifiedValue {
|
||||
// get the specification for this value. the associated function `try_from`
|
||||
// is essentially a left inverse of this method:
|
||||
//
|
||||
// SpecifiedValue::try_from(x.spec()) == Ok(x)
|
||||
//
|
||||
pub fn spec(&self) -> String {
|
||||
match self {
|
||||
Absent => String::new(),
|
||||
Present { spec, .. } => spec.clone()
|
||||
pub fn from_empty_spec() -> SpecifiedValue {
|
||||
SpecifiedValue { spec: String::new(), value: None }
|
||||
}
|
||||
|
||||
pub fn is_present(&self) -> bool {
|
||||
matches!(self.value, Some(_))
|
||||
}
|
||||
}
|
||||
|
||||
// we can try to turn a specification string into a `SpecifiedValue`. if the
|
||||
// specification is empty, the `SpecifiedValue` is `Absent`. if the
|
||||
// specification parses to a floating-point value `x`, the `SpecifiedValue` is
|
||||
// `Present`, with a `value` of `x`, and the specification is stored in `spec`.
|
||||
// these are currently the only valid specifications; any other produces an
|
||||
// error
|
||||
// a `SpecifiedValue` can be constructed from a specification string, formatted
|
||||
// as described in the comment on the structure definition. the result is `Ok`
|
||||
// if the specification is properly formatted, and `Error` if not
|
||||
impl TryFrom<String> for SpecifiedValue {
|
||||
type Error = ParseFloatError;
|
||||
|
||||
fn try_from(spec: String) -> Result<Self, Self::Error> {
|
||||
if spec.is_empty() {
|
||||
Ok(Absent)
|
||||
Ok(SpecifiedValue { spec: spec, value: None })
|
||||
} else {
|
||||
spec.parse::<f64>().map(
|
||||
|value| Present { spec: spec, value: value }
|
||||
|value| SpecifiedValue { spec: spec, value: Some(value) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue