diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 002b420..d30a371 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -1,14 +1,15 @@ use nalgebra::{DMatrix, DVector, DVectorView, Vector3}; use rustc_hash::FxHashMap; use slab::Slab; -use std::{collections::BTreeSet, sync::atomic::{AtomicU64, Ordering}}; +use std::{ + collections::BTreeSet, + num::ParseFloatError, + sync::atomic::{AtomicU64, Ordering} +}; use sycamore::prelude::*; 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}} -}; +use crate::engine::{Q, local_unif_to_std, realize_gram, ConfigSubspace, PartialMatrix}; // the types of the keys we use to access an assembly's elements and regulators pub type ElementKey = usize; @@ -117,6 +118,61 @@ impl Element { } } +// 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` +pub enum SpecifiedValue { + Absent, + Present { + spec: String, + value: f64 + } +} + +use SpecifiedValue::*; + +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() + } + } + + fn is_present(&self) -> bool { + match self { + Absent => false, + Present { .. } => true + } + } +} + +// 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 +impl TryFrom for SpecifiedValue { + type Error = ParseFloatError; + + fn try_from(spec: String) -> Result { + if spec.is_empty() { + Ok(Absent) + } else { + spec.parse::().map( + |value| Present { spec: spec, value: value } + ) + } + } +} + #[derive(Clone, Copy)] pub struct Regulator { pub subjects: (ElementKey, ElementKey), @@ -125,11 +181,13 @@ pub struct Regulator { } impl Regulator { - /* TO DO */ - // if it's called for, add a `set` method that takes a bare SpecifiedValue - pub fn set_if_ok(&self, set_pt_result: Result) { - if let Ok(set_pt) = set_pt_result { - self.set_point.set(set_pt); + pub fn try_set(&self, set_pt_spec: String) -> bool { + match SpecifiedValue::try_from(set_pt_spec) { + Ok(set_pt) => { + self.set_point.set(set_pt); + true + } + Err(_) => false } } } @@ -269,7 +327,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(); } }); diff --git a/app-proto/src/main.rs b/app-proto/src/main.rs index 6ab3e49..f961504 100644 --- a/app-proto/src/main.rs +++ b/app-proto/src/main.rs @@ -3,7 +3,6 @@ mod assembly; mod display; mod engine; mod outline; -mod specified; use rustc_hash::FxHashSet; use sycamore::prelude::*; diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index 31837bb..04bda9a 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -12,9 +12,9 @@ use crate::{ assembly::{ ElementKey, Regulator, - RegulatorKey - }, - specified::{SpecifiedValue, SpecifiedValue::{Absent, Present}} + RegulatorKey, + SpecifiedValue::* + } }; // an editable view of a regulator @@ -55,11 +55,9 @@ fn RegulatorInput(regulator: Regulator) -> View { }, placeholder=regulator.measurement.with(|result| result.to_string()), bind:value=value, - on:change=move |_| { - let set_pt_result = SpecifiedValue::try_from(value.get_clone_untracked()); - valid.set(set_pt_result.is_ok()); - regulator.set_if_ok(set_pt_result); - }, + on:change=move |_| valid.set( + regulator.try_set(value.get_clone_untracked()) + ), on:keydown={ move |event: KeyboardEvent| { match event.key().as_str() { diff --git a/app-proto/src/specified.rs b/app-proto/src/specified.rs deleted file mode 100644 index a943f2b..0000000 --- a/app-proto/src/specified.rs +++ /dev/null @@ -1,49 +0,0 @@ -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` -pub enum SpecifiedValue { - Absent, - Present { - spec: String, - value: 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() - } - } -} - -// 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 -impl TryFrom for SpecifiedValue { - type Error = ParseFloatError; - - fn try_from(spec: String) -> Result { - if spec.is_empty() { - Ok(Absent) - } else { - spec.parse::().map( - |value| Present { spec: spec, value: value } - ) - } - } -} \ No newline at end of file