-
Notifications
You must be signed in to change notification settings - Fork 16
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
Conversation
Revert StateVarReference back to StateVar
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, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
#[derive(Debug, Clone)] | ||
pub enum StateVariableUpdateRequest { | ||
SetEssentialValue(EssentialStateDescription), | ||
SetStateVar(ComponentStateDescription), |
There was a problem hiding this comment.
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 EssentialStateVar
s that are not referenced and therefore not needed...
What about the term Primitive
? We could have a PrimitiveValue
and DerivedValue
.
There was a problem hiding this comment.
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/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
} | ||
} | ||
|
||
fn get_action_names(&self) -> Vec<String> { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deferring until another PR.
Dispatch and process updates
create separate function for resolving.
packages/doenetml-worker-rust/doenetml-core/src/component/text.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
packages/doenetml-worker-rust/doenetml-core/src/state_var_calculations.rs
Outdated
Show resolved
Hide resolved
// so don't do anything to just continue the inner loop | ||
Freshness::Fresh => (), | ||
Freshness::Stale | Freshness::Resolved => { | ||
if !found_stale_or_resolved_dependency { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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]; |
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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.
No description provided.