Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement state variables in rust #86

Merged
merged 33 commits into from
Jan 10, 2024
Merged

Implement state variables in rust #86

merged 33 commits into from
Jan 10, 2024

Conversation

dqnykamp
Copy link
Member

@dqnykamp dqnykamp commented Jan 4, 2024

No description provided.

packages/doenetml-worker-rust/src/CoreWorker.ts Outdated Show resolved Hide resolved
impl From<serde_json::Number> for StateVarValue {
/// A json number will be converted to an integer if it is an integer.
///
/// For this reason, it's important that we can convert StateVarValue::Integer to f64,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there cases where we'd want to use BigInt instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't needed a BigInt yet, but I could imagine eventually folks will want it. I'm trying to build a structure where we can easily add additional data types.

packages/doenetml-worker-rust/src/CoreWorker.ts Outdated Show resolved Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/utils.rs Outdated Show resolved Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/utils.rs Outdated Show resolved Hide resolved
#[derive(Debug, Clone)]
pub enum StateVariableUpdateRequest {
SetEssentialValue(EssentialStateDescription),
SetStateVar(ComponentStateDescription),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the term Essential to be a bit confusing here, since to me it means "must be there", but there might be EssentialStateVars that are not referenced and therefore not needed...

What about the term Primitive? We could have a PrimitiveValue and DerivedValue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term Essential is intended to convey that these are the only state variables needed to reconstruct the document state (as every other state variable depends on them). When we write state to a database, we need only save the essential state. I think if an EssentialStateVar is not referenced, then it isn't even created. (I'd have to review the code more carefully to be certain of this last claim.)

packages/doenetml-worker-rust/doenetml-core/src/lib.rs Outdated Show resolved Hide resolved

/// A DependencyInstruction is used to make a Dependency based on the input document structure
#[derive(Debug)]
pub enum DependencyInstruction {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DependencyRequest seems like a better name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except that I've been using "request" to mean requested values for state variables, as in DependencyUpdatesRequested and StateVariableUpdateRequest. (I think I'll change the former to DependencyUpdateRequest for consistency.)

At the moment, I'm not able to come up with a better name that wouldn't be confused with DependencyUpdateRequest, but I'm open to suggestions!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that is such a bad conflict. You have a DepGetRequest and DepSetRequest. Seems like a common distinction.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried changing this to DependencyRequest and renaming the other to DependencyValueUpdateRequest but then ended up reverting that change as it got too confusing due to the DependencyValueUpdateRequest then referring to a request_idx rather than an instruction_idx. With the DependencyValueUpdateRequest overlapping with the "instructions", it was too confusing to call the instructions "requests".

I'm happy to revisit, but it became too hard to disambiguate them for now.

}
}

fn get_action_names(&self) -> Vec<String> {
Copy link
Contributor

@siefkenj siefkenj Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used for type checking, I assume?

I'm still not sure the best way to do this, but if you set up an enum and use

use strum_macros::{EnumString, EnumVariantNames};
use strum::VariantNames;

#[derive(EnumString, EnumVariantNames)]
#[strum("camelCase")]
enum Actions {
  UpdateImmediateValue,
  UpdateValue
}

then you can do Actions::VARIANTS to get a 'static vec of the string names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferring until another PR.

Copy link
Contributor

@siefkenj siefkenj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewritten function looks so much better!

match &dep.source {
DependencySource::StateVar {
component_idx,
state_var_idx,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're only using these to create a new pointer, you could implement into StateVarPointer and not de-structure this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this trait. The code is now shorter, but seems less explicit. I added some comments to explain what is going on. It seemed unnecessary to have a match since try_from did everything.

// so don't do anything to just continue the inner loop
Freshness::Fresh => (),
Freshness::Stale | Freshness::Resolved => {
if !found_stale_or_resolved_dependency {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really tracking whether state_var_ptr has already been re-added to the stack. Maybe call this variable state_var_ptr_on_stack? And set it to false as the first thing you do in the loop.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the variable name and added more comments. Hope it is clearer now.

if !found_stale_or_resolved_dependency {
// All the dependencies of state_var_ptr are fresh.
// We calculate its value if a dependency has changed,
// else restore its previous value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't quite get this part. We might need to talk about it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the variable name and added more comments. Hope it is clearer now.


{
let component = components[component_idx].borrow();
let state_var = &component.get_state_variables()[state_var_idx];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explicitly type this. rust-analyzer is having trouble...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something is wrong with your rust-analyzer! All of these types come directly from the assignment...

let component_idx = state_var_ptr.component_idx;
let state_var_idx = state_var_ptr.state_var_idx;

let dependency_instructions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explicitly type this. rust-analyzer is having trouble...

Copy link
Member Author

@dqnykamp dqnykamp Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange how my rust-analyzer doesn't have any trouble here or at the later spots.
It should able to infer it from later code.
But, it doesn't hurt to add it.

@dqnykamp dqnykamp marked this pull request as ready for review January 10, 2024 21:07
@dqnykamp dqnykamp merged commit 8c39141 into Doenet:0.7 Jan 10, 2024
1 check passed
@dqnykamp dqnykamp deleted the state-vars branch January 27, 2024 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants