Skip to content

Commit

Permalink
Implement state variables in rust (#86)
Browse files Browse the repository at this point in the history
* create state variable framework
* implement algorithm to calculate state variables
* handle actions to update state variables and send back flat dast updates
* match public state variables from macros, creating a state variable extend source

---------

Co-authored-by: Jason Siefken <siefkenj@gmail.com>
  • Loading branch information
dqnykamp and siefkenj authored Jan 10, 2024
1 parent 7182753 commit 8c39141
Show file tree
Hide file tree
Showing 31 changed files with 5,179 additions and 770 deletions.
12 changes: 7 additions & 5 deletions packages/doenetml-prototype/dev/testCode.doenet
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<textInput prefill="hi" />
<textInput prefill="hi" name="ti" />
The value: $ti.value
<!--

<p>Use this to <m>a < b</m>test DoenetML</p>
<p>A second paragraph! <text>with text</text></p>
<choiceInput>
Expand All @@ -9,12 +12,9 @@
<graph showNavigation>
<line through="(-8,8) (9,6)" />
<point>(2,3)</point>
<!--
<line through="(0,4)" slope="1/2" styleNumber="2" />

<line equation="y=2x-8" styleNumber="3" />
<line equation="x=-6" styleNumber="4" />
-->
</graph>
<section boxed>
<p>A lovely section.</p>
Expand All @@ -40,4 +40,6 @@

<section>
<p><lorem generateWords="10" /></p>
</section>
</section>

-->
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
import React from "react";
import { BasicComponent } from "../types";
import { useAppSelector } from "../../state/hooks";
import { useAppDispatch, useAppSelector } from "../../state/hooks";
import { renderingOnServerSelector } from "../../state/redux-slices/global";
import "./text-input.css";
import { coreActions } from "../../state/redux-slices/core";

export const TextInput: BasicComponent = ({ node }) => {
type TextInputData = { state: { immediateValue: string } };

export const TextInput: BasicComponent<TextInputData> = ({ node }) => {
const onServer = useAppSelector(renderingOnServerSelector);
const id = node.data.id;
const value = node.data.state.immediateValue;
const dispatch = useAppDispatch();

const updateValue = React.useCallback(() => {
dispatch(
coreActions.dispatchAction({
actionName: "updateValue",
componentIdx: id,
args: { text: value },
}),
);
}, [dispatch, value]);

if (onServer) {
return <span className="text-input"></span>;
return <span className="text-input">{value}</span>;
}

return (
<span className="text-input">
<label>
<input type="text" />
<input
type="text"
value={value}
onChange={(e) => {
dispatch(
coreActions.dispatchAction({
actionName: "updateImmediateValue",
componentIdx: id,
args: { text: e.target.value },
}),
);
}}
onBlur={updateValue}
onKeyUp={(e) => {
if (e.key === "Enter") {
updateValue();
}
}}
/>
</label>
</span>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as Comlink from "comlink";
import { createLoggingAsyncThunk } from "../../hooks";
import { CoreWorker } from "@doenet/doenetml-worker-rust";
import { Action, CoreWorker } from "@doenet/doenetml-worker-rust";
import { doenetGlobalConfig } from "../../../global-config";
import { RootState } from "../../store";
import { _coreReducerActions, selfSelector } from "./slice";
Expand Down Expand Up @@ -86,6 +86,23 @@ export const coreThunks = {
}
},
),
dispatchAction: createLoggingAsyncThunk(
"core/dispatchAction",
async (action: Action, { dispatch, getState }) => {
const worker = getWorker(getState());
if (worker == null) {
throw new Error("No worker loaded");
}

try {
const updates = await worker.dispatchAction(action);
dispatch(_dastReducerActions.processElementUpdates(updates));
} catch (e) {
dispatch(_coreReducerActions._setInErrorState(true));
console.warn(e);
}
},
),
};

export function getWorker(
Expand Down
38 changes: 37 additions & 1 deletion packages/doenetml-prototype/src/state/redux-slices/dast/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "../../store";
import { DastError, DastRoot } from "@doenet/parser";
import type { FlatDastRoot } from "@doenet/doenetml-worker-rust";
import type {
ElementUpdates,
FlatDastRoot,
} from "@doenet/doenetml-worker-rust";

// Define a type for the slice state
export interface DastState {
Expand Down Expand Up @@ -54,6 +57,39 @@ const dastSlice = createSlice({
state.flatDastRoot.elements[index] = element;
}
},
/**
* Process an `elementUpdate` coming from Core.
*/
processElementUpdates: (
state,
action: PayloadAction<ElementUpdates>,
) => {
for (const [id, update] of Object.entries(action.payload)) {
const elm = state.flatDastRoot.elements[Number(id)];
if (elm == null) {
console.error(
"Failed to find element in FlatDast with id =",
id,
"during element update request.",
);
continue;
}
if (elm.type === "error") {
throw new Error("Updating errors is not yet implemented");
}
if (update.changed_state) {
elm.data ??= { id: Number(id), state: {} };
elm.data.state ??= {};
Object.assign(elm.data.state, update.changed_state);
}
if (update.changed_attributes) {
console.warn("Updating attributes is not yet implemented");
}
if (update.new_children) {
elm.children = update.new_children;
}
}
},
},
});

Expand Down
8 changes: 5 additions & 3 deletions packages/doenetml-worker-rust/doenetml-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ ndarray = {version = "0.15.6", features = ["serde"]}
instant = { version = "0.1", features = [ "wasm-bindgen" ] }
strum = "0.25"
strum_macros = "0.25"
tailcall = "0.1.6"
enum_dispatch = "0.3.12"

[dev-dependencies]
criterion = "0.3.6"

[[bench]]
name = "my_benchmark"
harness = false
# [[bench]]
# name = "my_benchmark"
# harness = false



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ proc-macro = true
quote = "1"
proc-macro2 = "1.0"
syn = "2.0"
# syn = { version = "2.0", features = ["extra-traits"] }
convert_case = "0.5.0"
Loading

0 comments on commit 8c39141

Please sign in to comment.