forked from StudioInfinity/dyna3
Compare commits
2 commits
simplify-n
...
main
Author | SHA1 | Date | |
---|---|---|---|
af18a8e7d1 | |||
a4565281d5 |
12 changed files with 121 additions and 78 deletions
46
README.md
46
README.md
|
@ -25,32 +25,37 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter
|
|||
### Install the prerequisites
|
||||
|
||||
1. Install [`rustup`](https://rust-lang.github.io/rustup/): the officially recommended Rust toolchain manager
|
||||
* It's available on Ubuntu as a [Snap](https://snapcraft.io/rustup)
|
||||
- It's available on Ubuntu as a [Snap](https://snapcraft.io/rustup)
|
||||
2. Call `rustup default stable` to "download the latest stable release of Rust and set it as your default toolchain"
|
||||
* If you forget, the `rustup` [help system](https://github.com/rust-lang/rustup/blob/d9b3601c3feb2e88cf3f8ca4f7ab4fdad71441fd/src/errors.rs#L109-L112) will remind you
|
||||
- If you forget, the `rustup` [help system](https://github.com/rust-lang/rustup/blob/d9b3601c3feb2e88cf3f8ca4f7ab4fdad71441fd/src/errors.rs#L109-L112) will remind you
|
||||
3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html)
|
||||
4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/)
|
||||
5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool
|
||||
6. Add the `.cargo/bin` folder in your home directory to your executable search path
|
||||
* This lets you call Trunk, and other tools installed by Cargo, without specifying their paths
|
||||
* On POSIX systems, the search path is stored in the `PATH` environment variable
|
||||
- This lets you call Trunk, and other tools installed by Cargo, without specifying their paths
|
||||
- On POSIX systems, the search path is stored in the `PATH` environment variable
|
||||
|
||||
### Play with the prototype
|
||||
|
||||
1. From the `app-proto` folder, call `trunk serve --release` to build and serve the prototype
|
||||
* *The crates the prototype depends on will be downloaded and served automatically*
|
||||
* *For a faster build, at the expense of a much slower prototype, you can call `trunk serve` without the `--release` flag*
|
||||
* *If you want to stay in the top-level folder, you can call `trunk serve --config app-proto [--release]`* from there instead.
|
||||
- The crates the prototype depends on will be downloaded and served automatically
|
||||
- For a faster build, at the expense of a much slower prototype, you can call `trunk serve` without the `--release` flag
|
||||
- If you want to stay in the top-level folder, you can call `trunk serve --config app-proto [--release]` from there instead.
|
||||
3. In a web browser, visit one of the URLs listed under the message `INFO 📡 server listening at:`
|
||||
* *Touching any file in the `app-proto` folder will make Trunk rebuild and live-reload the prototype*
|
||||
- Touching any file in the `app-proto` folder will make Trunk rebuild and live-reload the prototype
|
||||
4. Press *ctrl+C* in the shell where Trunk is running to stop serving the prototype
|
||||
|
||||
### Run the engine on some example problems
|
||||
|
||||
1. Go into the `app-proto` folder
|
||||
2. Call `./run-examples`
|
||||
* *For each example problem, the engine will print the value of the loss function at each optimization step*
|
||||
* *The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then*
|
||||
1. Use `sh` to run the script `tools/run-examples.sh`
|
||||
- The script is location-independent, so you can do this from anywhere in the dyna3 repository
|
||||
- The call from the top level of the repository is:
|
||||
|
||||
```bash
|
||||
sh tools/run-examples.sh
|
||||
```
|
||||
- For each example problem, the engine will print the value of the loss function at each optimization step
|
||||
- The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then
|
||||
|
||||
```julia
|
||||
include("irisawa-hexlet.jl")
|
||||
|
@ -59,9 +64,24 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter
|
|||
end
|
||||
```
|
||||
|
||||
*you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show*
|
||||
you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show
|
||||
|
||||
### Run the automated tests
|
||||
|
||||
1. Go into the `app-proto` folder
|
||||
2. Call `cargo test`
|
||||
|
||||
### Deploy the prototype
|
||||
|
||||
1. From the `app-proto` folder, call `trunk build --release`
|
||||
- Building in [release mode](https://doc.rust-lang.org/cargo/reference/profiles.html#release) produces an executable which is smaller and often much faster, but harder to debug and more time-consuming to build
|
||||
- If you want to stay in the top-level folder, you can call `trunk build --config app-proto --release` from there instead
|
||||
2. Use `sh` to run the packaging script `tools/package-for-deployment.sh`.
|
||||
- The script is location-independent, so you can do this from anywhere in the dyna3 repository
|
||||
- The call from the top level of the repository is:
|
||||
```bash
|
||||
sh tools/package-for-deployment.sh
|
||||
```
|
||||
- This will overwrite or replace the files in `deploy/dyna3`
|
||||
3. Put the contents of `deploy/dyna3` in the folder on your server that the prototype will be served from.
|
||||
- To simplify uploading, you might want to combine these files into an archive called `deploy/dyna3.zip`. Git has been set to ignore this path
|
2
app-proto/Trunk.toml
Normal file
2
app-proto/Trunk.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
public_url = "./"
|
|
@ -175,8 +175,8 @@ impl Sphere {
|
|||
label: String,
|
||||
color: ElementColor,
|
||||
representation: DVector<f64>,
|
||||
) -> Sphere {
|
||||
Sphere {
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
label,
|
||||
color,
|
||||
|
@ -194,8 +194,8 @@ impl Element for Sphere {
|
|||
"sphere".to_string()
|
||||
}
|
||||
|
||||
fn default(id: String, id_num: u64) -> Sphere {
|
||||
Sphere::new(
|
||||
fn default(id: String, id_num: u64) -> Self {
|
||||
Self::new(
|
||||
id,
|
||||
format!("Sphere {id_num}"),
|
||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||
|
@ -275,8 +275,8 @@ impl Point {
|
|||
label: String,
|
||||
color: ElementColor,
|
||||
representation: DVector<f64>,
|
||||
) -> Point {
|
||||
Point {
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
label,
|
||||
color,
|
||||
|
@ -294,8 +294,8 @@ impl Element for Point {
|
|||
"point".to_string()
|
||||
}
|
||||
|
||||
fn default(id: String, id_num: u64) -> Point {
|
||||
Point::new(
|
||||
fn default(id: String, id_num: u64) -> Self {
|
||||
Self::new(
|
||||
id,
|
||||
format!("Point {id_num}"),
|
||||
[0.75_f32, 0.75_f32, 0.75_f32],
|
||||
|
@ -348,7 +348,7 @@ impl ProblemPoser for Point {
|
|||
format!("Point \"{}\" should be indexed before writing problem data", self.id).as_str()
|
||||
);
|
||||
problem.gram.push_sym(index, index, 0.0);
|
||||
problem.frozen.push(Point::WEIGHT_COMPONENT, index, 0.5);
|
||||
problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5);
|
||||
problem.guess.set_column(index, &self.representation.get_clone_untracked());
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ pub struct InversiveDistanceRegulator {
|
|||
}
|
||||
|
||||
impl InversiveDistanceRegulator {
|
||||
pub fn new(subjects: [Rc<dyn Element>; 2]) -> InversiveDistanceRegulator {
|
||||
pub fn new(subjects: [Rc<dyn Element>; 2]) -> Self {
|
||||
let representations = subjects.each_ref().map(|subj| subj.representation());
|
||||
let measurement = create_memo(move || {
|
||||
representations[0].with(|rep_0|
|
||||
|
@ -406,7 +406,7 @@ impl InversiveDistanceRegulator {
|
|||
let set_point = create_signal(SpecifiedValue::from_empty_spec());
|
||||
let serial = Self::next_serial();
|
||||
|
||||
InversiveDistanceRegulator { subjects, measurement, set_point, serial }
|
||||
Self { subjects, measurement, set_point, serial }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ pub struct HalfCurvatureRegulator {
|
|||
}
|
||||
|
||||
impl HalfCurvatureRegulator {
|
||||
pub fn new(subject: Rc<dyn Element>) -> HalfCurvatureRegulator {
|
||||
pub fn new(subject: Rc<dyn Element>) -> Self {
|
||||
let measurement = subject.representation().map(
|
||||
|rep| rep[Sphere::CURVATURE_COMPONENT]
|
||||
);
|
||||
|
@ -461,7 +461,7 @@ impl HalfCurvatureRegulator {
|
|||
let set_point = create_signal(SpecifiedValue::from_empty_spec());
|
||||
let serial = Self::next_serial();
|
||||
|
||||
HalfCurvatureRegulator { subject, measurement, set_point, serial }
|
||||
Self { subject, measurement, set_point, serial }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ struct DiagnosticsState {
|
|||
}
|
||||
|
||||
impl DiagnosticsState {
|
||||
fn new(initial_tab: String) -> DiagnosticsState {
|
||||
DiagnosticsState { active_tab: create_signal(initial_tab) }
|
||||
fn new(initial_tab: String) -> Self {
|
||||
Self { active_tab: create_signal(initial_tab) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ struct SceneSpheres {
|
|||
}
|
||||
|
||||
impl SceneSpheres {
|
||||
fn new() -> SceneSpheres {
|
||||
SceneSpheres {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
representations: Vec::new(),
|
||||
colors_with_opacity: Vec::new(),
|
||||
highlights: Vec::new(),
|
||||
|
@ -71,8 +71,8 @@ struct ScenePoints {
|
|||
}
|
||||
|
||||
impl ScenePoints {
|
||||
fn new() -> ScenePoints {
|
||||
ScenePoints {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
representations: Vec::new(),
|
||||
colors_with_opacity: Vec::new(),
|
||||
highlights: Vec::new(),
|
||||
|
@ -97,8 +97,8 @@ pub struct Scene {
|
|||
}
|
||||
|
||||
impl Scene {
|
||||
fn new() -> Scene {
|
||||
Scene {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
spheres: SceneSpheres::new(),
|
||||
points: ScenePoints::new(),
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ use crate::{
|
|||
// done more work on saving and loading assemblies, we should come back to this
|
||||
// code to see if it can be simplified
|
||||
|
||||
fn load_gen_assemb(assembly: &Assembly) {
|
||||
fn load_general(assembly: &Assembly) {
|
||||
let _ = assembly.try_insert_element(
|
||||
Sphere::new(
|
||||
String::from("gemini_a"),
|
||||
|
@ -77,7 +77,7 @@ fn load_gen_assemb(assembly: &Assembly) {
|
|||
);
|
||||
}
|
||||
|
||||
fn load_low_curv_assemb(assembly: &Assembly) {
|
||||
fn load_low_curvature(assembly: &Assembly) {
|
||||
// create the spheres
|
||||
let a = 0.75_f64.sqrt();
|
||||
let _ = assembly.try_insert_element(
|
||||
|
@ -196,7 +196,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_pointed_assemb(assembly: &Assembly) {
|
||||
fn load_pointed(assembly: &Assembly) {
|
||||
let _ = assembly.try_insert_element(
|
||||
Point::new(
|
||||
format!("point_front"),
|
||||
|
@ -246,7 +246,7 @@ fn load_pointed_assemb(assembly: &Assembly) {
|
|||
// B-C "
|
||||
// C-C "
|
||||
// A-C -0.25 * φ^2 = -0.6545084971874737
|
||||
fn load_tridim_icosahedron_assemb(assembly: &Assembly) {
|
||||
fn load_tridiminished_icosahedron(assembly: &Assembly) {
|
||||
// create the vertices
|
||||
const COLOR_A: ElementColor = [1.00_f32, 0.25_f32, 0.25_f32];
|
||||
const COLOR_B: ElementColor = [0.75_f32, 0.75_f32, 0.75_f32];
|
||||
|
@ -409,7 +409,7 @@ fn load_tridim_icosahedron_assemb(assembly: &Assembly) {
|
|||
|
||||
// to finish describing the dodecahedral circle packing, set the inversive
|
||||
// distance regulators to -1. some of the regulators have already been set
|
||||
fn load_dodeca_packing_assemb(assembly: &Assembly) {
|
||||
fn load_dodecahedral_packing(assembly: &Assembly) {
|
||||
// add the substrate
|
||||
let _ = assembly.try_insert_element(
|
||||
Sphere::new(
|
||||
|
@ -550,7 +550,7 @@ fn load_dodeca_packing_assemb(assembly: &Assembly) {
|
|||
|
||||
// the initial configuration of this test assembly deliberately violates the
|
||||
// constraints, so loading the assembly will trigger a non-trivial realization
|
||||
fn load_balanced_assemb(assembly: &Assembly) {
|
||||
fn load_balanced(assembly: &Assembly) {
|
||||
// create the spheres
|
||||
const R_OUTER: f64 = 10.0;
|
||||
const R_INNER: f64 = 4.0;
|
||||
|
@ -611,7 +611,7 @@ fn load_balanced_assemb(assembly: &Assembly) {
|
|||
|
||||
// the initial configuration of this test assembly deliberately violates the
|
||||
// constraints, so loading the assembly will trigger a non-trivial realization
|
||||
fn load_off_center_assemb(assembly: &Assembly) {
|
||||
fn load_off_center(assembly: &Assembly) {
|
||||
// create a point almost at the origin and a sphere centered on the origin
|
||||
let _ = assembly.try_insert_element(
|
||||
Point::new(
|
||||
|
@ -648,7 +648,7 @@ fn load_off_center_assemb(assembly: &Assembly) {
|
|||
// sqrt(1/6) and sqrt(3/2), respectively. to measure those radii, set an
|
||||
// inversive distance of -1 between the insphere and each face, and then set an
|
||||
// inversive distance of 0 between the circumsphere and each vertex
|
||||
fn load_radius_ratio_assemb(assembly: &Assembly) {
|
||||
fn load_radius_ratio(assembly: &Assembly) {
|
||||
let index_range = 1..=4;
|
||||
|
||||
// create the spheres
|
||||
|
@ -789,7 +789,7 @@ fn load_radius_ratio_assemb(assembly: &Assembly) {
|
|||
// conditions are exactly representable as floats, unlike the analogous numbers
|
||||
// in the scaled-up problem. the inexact representations might break the
|
||||
// symmetry that's getting the engine stuck
|
||||
fn load_irisawa_hexlet_assemb(assembly: &Assembly) {
|
||||
fn load_irisawa_hexlet(assembly: &Assembly) {
|
||||
let index_range = 1..=6;
|
||||
let colors = [
|
||||
[1.00_f32, 0.00_f32, 0.25_f32],
|
||||
|
@ -909,15 +909,15 @@ pub fn TestAssemblyChooser() -> View {
|
|||
|
||||
// load assembly
|
||||
match name.as_str() {
|
||||
"general" => load_gen_assemb(assembly),
|
||||
"low-curv" => load_low_curv_assemb(assembly),
|
||||
"pointed" => load_pointed_assemb(assembly),
|
||||
"tridim-icosahedron" => load_tridim_icosahedron_assemb(assembly),
|
||||
"dodeca-packing" => load_dodeca_packing_assemb(assembly),
|
||||
"balanced" => load_balanced_assemb(assembly),
|
||||
"off-center" => load_off_center_assemb(assembly),
|
||||
"radius-ratio" => load_radius_ratio_assemb(assembly),
|
||||
"irisawa-hexlet" => load_irisawa_hexlet_assemb(assembly),
|
||||
"general" => load_general(assembly),
|
||||
"low-curvature" => load_low_curvature(assembly),
|
||||
"pointed" => load_pointed(assembly),
|
||||
"tridiminished-icosahedron" => load_tridiminished_icosahedron(assembly),
|
||||
"dodecahedral-packing" => load_dodecahedral_packing(assembly),
|
||||
"balanced" => load_balanced(assembly),
|
||||
"off-center" => load_off_center(assembly),
|
||||
"radius-ratio" => load_radius_ratio(assembly),
|
||||
"irisawa-hexlet" => load_irisawa_hexlet(assembly),
|
||||
_ => (),
|
||||
};
|
||||
});
|
||||
|
@ -927,10 +927,10 @@ pub fn TestAssemblyChooser() -> View {
|
|||
view! {
|
||||
select(bind:value = assembly_name) {
|
||||
option(value = "general") { "General" }
|
||||
option(value = "low-curv") { "Low-curvature" }
|
||||
option(value = "low-curvature") { "Low-curvature" }
|
||||
option(value = "pointed") { "Pointed" }
|
||||
option(value = "tridim-icosahedron") { "Tridiminished icosahedron" }
|
||||
option(value = "dodeca-packing") { "Dodecahedral packing" }
|
||||
option(value = "tridiminished-icosahedron") { "Tridiminished icosahedron" }
|
||||
option(value = "dodecahedral-packing") { "Dodecahedral packing" }
|
||||
option(value = "balanced") { "Balanced" }
|
||||
option(value = "off-center") { "Off-center" }
|
||||
option(value = "radius-ratio") { "Radius ratio" }
|
||||
|
|
|
@ -59,12 +59,12 @@ pub struct MatrixEntry {
|
|||
pub struct PartialMatrix(Vec<MatrixEntry>);
|
||||
|
||||
impl PartialMatrix {
|
||||
pub fn new() -> PartialMatrix {
|
||||
PartialMatrix(Vec::<MatrixEntry>::new())
|
||||
pub fn new() -> Self {
|
||||
Self(Vec::<MatrixEntry>::new())
|
||||
}
|
||||
|
||||
pub fn push(&mut self, row: usize, col: usize, value: f64) {
|
||||
let PartialMatrix(entries) = self;
|
||||
let Self(entries) = self;
|
||||
entries.push(MatrixEntry { index: (row, col), value });
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ impl IntoIterator for PartialMatrix {
|
|||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let PartialMatrix(entries) = self;
|
||||
let Self(entries) = self;
|
||||
entries.into_iter()
|
||||
}
|
||||
}
|
||||
|
@ -139,8 +139,8 @@ pub struct ConfigSubspace {
|
|||
}
|
||||
|
||||
impl ConfigSubspace {
|
||||
pub fn zero(assembly_dim: usize) -> ConfigSubspace {
|
||||
ConfigSubspace {
|
||||
pub fn zero(assembly_dim: usize) -> Self {
|
||||
Self {
|
||||
assembly_dim,
|
||||
basis_proj: Vec::new(),
|
||||
basis_std: Vec::new(),
|
||||
|
@ -154,7 +154,7 @@ impl ConfigSubspace {
|
|||
a: DMatrix<f64>,
|
||||
proj_to_std: DMatrix<f64>,
|
||||
assembly_dim: usize,
|
||||
) -> ConfigSubspace {
|
||||
) -> Self {
|
||||
// find a basis for the kernel. the basis is expressed in the projection
|
||||
// coordinates, and it's orthonormal with respect to the projection
|
||||
// inner product
|
||||
|
@ -173,7 +173,7 @@ impl ConfigSubspace {
|
|||
|
||||
const ELEMENT_DIM: usize = 5;
|
||||
const UNIFORM_DIM: usize = 4;
|
||||
ConfigSubspace {
|
||||
Self {
|
||||
assembly_dim,
|
||||
basis_std: basis_std.column_iter().map(
|
||||
|v| Into::<DMatrix<f64>>::into(
|
||||
|
@ -224,8 +224,8 @@ pub struct DescentHistory {
|
|||
}
|
||||
|
||||
impl DescentHistory {
|
||||
pub fn new() -> DescentHistory {
|
||||
DescentHistory {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
config: Vec::<DMatrix<f64>>::new(),
|
||||
scaled_loss: Vec::<f64>::new(),
|
||||
neg_grad: Vec::<DMatrix<f64>>::new(),
|
||||
|
@ -245,9 +245,9 @@ pub struct ConstraintProblem {
|
|||
}
|
||||
|
||||
impl ConstraintProblem {
|
||||
pub fn new(element_count: usize) -> ConstraintProblem {
|
||||
pub fn new(element_count: usize) -> Self {
|
||||
const ELEMENT_DIM: usize = 5;
|
||||
ConstraintProblem {
|
||||
Self {
|
||||
gram: PartialMatrix::new(),
|
||||
frozen: PartialMatrix::new(),
|
||||
guess: DMatrix::<f64>::zeros(ELEMENT_DIM, element_count),
|
||||
|
@ -255,8 +255,8 @@ impl ConstraintProblem {
|
|||
}
|
||||
|
||||
#[cfg(feature = "dev")]
|
||||
pub fn from_guess(guess_columns: &[DVector<f64>]) -> ConstraintProblem {
|
||||
ConstraintProblem {
|
||||
pub fn from_guess(guess_columns: &[DVector<f64>]) -> Self {
|
||||
Self {
|
||||
gram: PartialMatrix::new(),
|
||||
frozen: PartialMatrix::new(),
|
||||
guess: DMatrix::from_columns(guess_columns),
|
||||
|
@ -284,10 +284,10 @@ struct SearchState {
|
|||
}
|
||||
|
||||
impl SearchState {
|
||||
fn from_config(gram: &PartialMatrix, config: DMatrix<f64>) -> SearchState {
|
||||
fn from_config(gram: &PartialMatrix, config: DMatrix<f64>) -> Self {
|
||||
let err_proj = gram.sub_proj(&(config.tr_mul(&*Q) * &config));
|
||||
let loss = err_proj.norm_squared();
|
||||
SearchState { config, err_proj, loss }
|
||||
Self { config, err_proj, loss }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ struct AppState {
|
|||
}
|
||||
|
||||
impl AppState {
|
||||
fn new() -> AppState {
|
||||
AppState {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
assembly: Assembly::new(),
|
||||
selection: create_signal(BTreeSet::default()),
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ pub struct SpecifiedValue {
|
|||
}
|
||||
|
||||
impl SpecifiedValue {
|
||||
pub fn from_empty_spec() -> SpecifiedValue {
|
||||
SpecifiedValue { spec: String::new(), value: None }
|
||||
pub fn from_empty_spec() -> Self {
|
||||
Self { spec: String::new(), value: None }
|
||||
}
|
||||
|
||||
pub fn is_present(&self) -> bool {
|
||||
|
@ -34,10 +34,10 @@ impl TryFrom<String> for SpecifiedValue {
|
|||
|
||||
fn try_from(spec: String) -> Result<Self, Self::Error> {
|
||||
if spec.is_empty() {
|
||||
Ok(SpecifiedValue::from_empty_spec())
|
||||
Ok(Self::from_empty_spec())
|
||||
} else {
|
||||
spec.parse::<f64>().map(
|
||||
|value| SpecifiedValue { spec, value: Some(value) }
|
||||
|value| Self { spec, value: Some(value) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
5
deploy/.gitignore
vendored
Normal file
5
deploy/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/dyna3.zip
|
||||
/dyna3/index.html
|
||||
/dyna3/dyna3-*.js
|
||||
/dyna3/dyna3-*.wasm
|
||||
/dyna3/main-*.css
|
16
tools/package-for-deployment.sh
Normal file
16
tools/package-for-deployment.sh
Normal file
|
@ -0,0 +1,16 @@
|
|||
# set paths. this technique for getting the script location comes from
|
||||
# `mklement0` on Stack Overflow
|
||||
#
|
||||
# https://stackoverflow.com/a/24114056
|
||||
#
|
||||
TOOLS=$(dirname -- $0)
|
||||
SRC="$TOOLS/../app-proto/dist"
|
||||
DEST="$TOOLS/../deploy/dyna3"
|
||||
|
||||
# remove the old hash-named files
|
||||
[ -e "$DEST"/dyna3-*.js ] && rm "$DEST"/dyna3-*.js
|
||||
[ -e "$DEST"/dyna3-*.wasm ] && rm "$DEST"/dyna3-*.wasm
|
||||
[ -e "$DEST"/main-*.css ] && rm "$DEST"/main-*.css
|
||||
|
||||
# copy the distribution
|
||||
cp -r "$SRC/." "$DEST"
|
|
@ -8,7 +8,7 @@
|
|||
# the application prototype
|
||||
|
||||
# find the manifest file for the application prototype
|
||||
MANIFEST="$(dirname -- $0)/Cargo.toml"
|
||||
MANIFEST="$(dirname -- $0)/../app-proto/Cargo.toml"
|
||||
|
||||
# set up the command that runs each example
|
||||
RUN_EXAMPLE="cargo run --manifest-path $MANIFEST --example"
|
Loading…
Add table
Add a link
Reference in a new issue