Skip to content

refactor: remove unnecessary clone from eval logic#857

Open
ayushjain17 wants to merge 1 commit intomainfrom
refactor/cloning
Open

refactor: remove unnecessary clone from eval logic#857
ayushjain17 wants to merge 1 commit intomainfrom
refactor/cloning

Conversation

@ayushjain17
Copy link
Collaborator

@ayushjain17 ayushjain17 commented Feb 1, 2026

Problem

Too much unnecessary cloning of data in eval logic

Solution

Take ownership of data in functions wherever necessary instead of borrowing and then cloning inside the functions, allowing the caller functions to decide upon necessary cloning and ownership transfer

Summary by CodeRabbit

Release Notes

  • Breaking Changes

    • API signatures for configuration and variant evaluation functions have been updated; callers may need to adjust parameter passing patterns.
  • Refactoring

    • Restructured internal data flow patterns throughout configuration and variant resolution paths.
    • Removed serde_json dependency from core libraries.
  • New Features

    • Added utility methods for accessing inner data structures.
    • Added FFI helpers for connectivity validation and safe memory deallocation.

@semanticdiff-com
Copy link

semanticdiff-com bot commented Feb 1, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  crates/context_aware_config/src/api/context/helpers.rs  95% smaller
  crates/context_aware_config/src/api/context/handlers.rs  95% smaller
  crates/context_aware_config/src/api/config/helpers.rs  94% smaller
  crates/experimentation_client/src/interface.rs  93% smaller
  crates/superposition_types/src/logic/tests.rs  91% smaller
  crates/superposition_provider/src/provider.rs  81% smaller
  crates/superposition_types/src/config.rs  56% smaller
  crates/cac_client/src/lib.rs  49% smaller
  crates/superposition_provider/src/utils.rs  49% smaller
  crates/superposition_core/src/ffi.rs  46% smaller
  crates/superposition_core/src/ffi_legacy.rs  42% smaller
  crates/superposition_types/src/logic.rs  40% smaller
  crates/context_aware_config/src/api/config/handlers.rs  39% smaller
  crates/cac_client/src/eval.rs  30% smaller
  crates/superposition_core/src/config.rs  29% smaller
  crates/superposition_provider/src/client.rs  20% smaller
  crates/superposition/src/resolve/handlers.rs  13% smaller
  Cargo.lock Unsupported file format
  crates/experimentation_client/src/lib.rs  0% smaller
  crates/experimentation_platform/src/api/experiments/handlers.rs  0% smaller
  crates/superposition/Cargo.toml Unsupported file format
  crates/superposition_core/src/experiment.rs  0% smaller
  crates/superposition_core/src/toml/test.rs  0% smaller
  crates/superposition_core/tests/test_filter_debug.rs  0% smaller
  crates/superposition_types/src/config/tests.rs  0% smaller
  crates/superposition_types/src/custom_query.rs  0% smaller
  examples/experimentation_client_integration_example/src/main.rs  0% smaller
  examples/superposition_toml_example/src/main.rs  0% smaller

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR refactors ownership semantics across the codebase, shifting evaluation and configuration functions from borrowing references to accepting owned values. Public API signatures are updated for eval_config, eval_config_with_reasoning, filter_by_dimensions, get_applicable_variants, and local cohort evaluation functions. Internal implementations reduce cloning and use in-place mutations, with corresponding updates across FFI boundaries, call sites, and tests.

Changes

Cohort / File(s) Summary
Core evaluation functions
crates/superposition_core/src/config.rs
eval_config and eval_config_with_reasoning now accept owned parameters (Vec, HashMap<String, Overrides>, etc.) instead of references; merge function signature changed to accept owned patch Value; get_overrides uses remove instead of get for in-place override mutation; merge_overrides_on_default_config now returns owned Map instead of mutating by reference; replaced replace_top_level with inlined logic.
Type system updates
crates/superposition_types/src/config.rs, crates/superposition_types/src/custom_query.rs
Added into_inner methods to Overrides and QueryMap for exposing inner Map<String, Value>; Config::filter_by_dimensions changed to consume self and take owned Map, using local remove-based override filtering; returns owned Config with moved dimensions.
Local cohort evaluation
crates/superposition_types/src/logic.rs
evaluate_local_cohorts and evaluate_local_cohorts_skip_unresolved now accept owned HashMap<String, DimensionInfo> and Map<String, Value> instead of references; _evaluate_local_cohorts updated to match; refactored dimension traversal to reduce cloning and use references internally where appropriate.
Integration in core
crates/superposition_core/src/experiment.rs, crates/superposition_core/src/ffi.rs, crates/superposition_core/src/ffi_legacy.rs
get_applicable_variants signature changed to accept owned dimensions_info and query_data; EvalFn type updated to accept Vec, HashMap<String, Overrides>, HashMap<String, DimensionInfo>, Map<String, Value>; FFI entry points updated; ffi_legacy adds core_test_connection and core_free_string helpers.
Client-side provider updates
crates/experimentation_client/src/lib.rs, crates/experimentation_client/src/interface.rs
get_applicable_variant now accepts owned HashMap<String, DimensionInfo> and Map<String, Value>; interface FFI calls updated to pass owned values; evaluate_local_cohorts calls switched to owned parameter passing.
Config and experimentation handlers
crates/context_aware_config/src/api/config/handlers.rs, crates/context_aware_config/src/api/config/helpers.rs, crates/experimentation_platform/src/api/experiments/handlers.rs
resolve function signature changed to accept Config by value instead of &mut Config; get_handler and resolve_handler updated; get_applicable_variants_helper accepts dimensions_info by value; all call sites adjusted for owned parameter passing.
Provider implementations
crates/superposition_provider/src/client.rs, crates/superposition_provider/src/provider.rs, crates/superposition_provider/src/utils.rs
CacConfig fields and methods updated to use Map instead of serde_json::Map; evaluate_config takes owned Map<String, Value>; get_applicable_variants accepts owned dimensions_info and contexts; ConversionUtils::evaluate_config changed to consume Config and Map.
Test updates
crates/superposition_types/src/config/tests.rs, crates/superposition_types/src/logic/tests.rs, examples/experimentation_client_integration_example/src/main.rs
Tests updated to call clone().filter_by_dimensions(...) and pass owned values to evaluate_local_cohorts; test helper calls adjusted for new ownership semantics.
Dependency cleanup
crates/superposition/Cargo.toml, crates/cac_client/src/eval.rs, crates/cac_client/src/lib.rs, crates/context_aware_config/src/api/context/handlers.rs, crates/context_aware_config/src/api/context/helpers.rs
Removed serde_json dependency from superposition; CAC client eval refactored to accept owned Config and Map; context handlers and helpers updated to use into_inner for owned value extraction; updated override merging to eliminate clones.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

quick win

Suggested reviewers

  • knutties
  • Datron
  • mahatoankitkumar

Poem

🐰 From borrowed refs to values owned,
The cohorts dance, no longer loaned,
With cloning cut and moves set free,
The codebase flows more gracefully! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: remove unnecessary clone from eval logic' accurately describes the primary objective of this changeset, which systematically shifts from borrowing-and-cloning patterns to ownership-based semantics across evaluation functions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/cloning

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ayushjain17 ayushjain17 changed the title refactor: remove unnecessary from eval logic refactor: remove unnecessary clone from eval logic Feb 3, 2026
@ayushjain17 ayushjain17 marked this pull request as ready for review February 8, 2026 13:15
@ayushjain17 ayushjain17 requested a review from a team as a code owner February 8, 2026 13:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/superposition_core/src/ffi_legacy.rs (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Stale file-level comment: // src/ffi.rs doesn't match filename ffi_legacy.rs.

Proposed fix
-// src/ffi.rs
+// src/ffi_legacy.rs
🤖 Fix all issues with AI agents
In `@crates/superposition_types/src/config.rs`:
- Around line 292-317: In filter_by_dimensions, remove the unnecessary clone of
self.contexts and pass ownership directly to Context::filter_by_eval (i.e., call
Context::filter_by_eval(self.contexts, &modified_context)) since
filter_by_dimensions consumes self and contexts is not used afterward; update
the call site in the function where filtered_context is created (referencing
Context::filter_by_eval and self.contexts) so you avoid the clone and retain the
existing use of self.overrides via let mut overrides = self.overrides.
🧹 Nitpick comments (4)
crates/superposition_provider/src/utils.rs (1)

654-670: Remaining clones inside the function body could be eliminated.

Since config (and thus final_config) is now owned, you can avoid the .clone() calls on lines 655 and 658 by destructuring the owned struct:

♻️ Suggested refactor
-        // Start with default configs
-        let mut result = final_config.default_configs.clone();
-
-        // Apply overrides based on context priority (higher priority wins)
-        let mut sorted_contexts = final_config.contexts.clone();
-        sorted_contexts.sort_by_key(|c| std::cmp::Reverse(c.priority)); // Sort by priority descending
+        let Config { default_configs: mut result, mut contexts: sorted_contexts, overrides, .. } = final_config;
+        sorted_contexts.sort_by_key(|c| std::cmp::Reverse(c.priority));
 
         for context in sorted_contexts {
             if let Some(override_key) = context.override_with_keys.first() {
-                if let Some(overrides) = final_config.overrides.get(override_key) {
-                    let override_map: Map<String, Value> = overrides.clone().into();
+                if let Some(overrides) = overrides.get(override_key) {
+                    let override_map: Map<String, Value> = overrides.clone().into();
                     for (override_key, value) in override_map {
                         result.insert(override_key, value);
crates/superposition_provider/src/client.rs (1)

217-246: Remove unnecessary clone of default_configs on line 227.

The eval_config function signature in crates/superposition_core/src/config.rs takes default_configs: Map<String, Value> by value. Since cached_config is already an owned Config (from to_owned() on line 223) and the field is moved immediately without reuse, the .clone() is unnecessary. This matches the pattern used for the other fields (contexts, overrides, dimensions) which are moved without cloning.

Suggested fix
                eval_config(
-                   cached_config.default_configs.clone(),
+                   cached_config.default_configs,
                    cached_config.contexts,
                    cached_config.overrides,
                    cached_config.dimensions,
crates/superposition_core/src/config.rs (1)

144-163: overrides.remove() is a nice touch to avoid cloning override values.

One minor observation: in the REPLACE branch (line 147), on_override_select(context) is guarded by the if let Some(doc) check, while in the MERGE branch (line 159) it's unconditional. Since required_overrides is always initialized as json!({}), as_object_mut() will always succeed, so in practice the behavior is identical. However, for clarity and consistency you could consider moving the on_override_select call outside the if let in the REPLACE arm — or restructuring so both branches look symmetric.

♻️ Optional: make both branches symmetric
                     MergeStrategy::REPLACE => {
                         if let Some(doc) = required_overrides.as_object_mut() {
                             for (key, value) in overriden_value.into_inner() {
                                 doc.insert(key, value);
                             }
-                            on_override_select(context)
                         }
+                        on_override_select(context);
                     }
crates/superposition_core/src/ffi.rs (1)

143-144: Unnecessary query_data.clone()query_data is not used after this line.

Since json_from_map takes ownership and query_data has no further uses, you can pass it directly.

♻️ Remove unnecessary clone
-    let _query_data = json_from_map(query_data.clone())
+    let _query_data = json_from_map(query_data)

Comment on lines 292 to 317
pub fn filter_by_dimensions(self, dimension_data: Map<String, Value>) -> Self {
let modified_context = evaluate_local_cohorts_skip_unresolved(
self.dimensions.clone(),
dimension_data,
);

let filtered_context =
Context::filter_by_eval(self.contexts.clone(), &modified_context);

let mut overrides = self.overrides;
let filtered_overrides: HashMap<String, Overrides> = filtered_context
.iter()
.flat_map(|ele| {
let override_with_key = ele.override_with_keys.get_key();
self.overrides
.get(override_with_key)
.map(|value| (override_with_key.to_string(), value.clone()))
overrides
.remove(override_with_key)
.map(|value| (override_with_key.to_string(), value))
})
.collect();

Self {
contexts: filtered_context,
overrides: filtered_overrides,
default_configs: self.default_configs.clone(),
dimensions: self.dimensions.clone(),
default_configs: self.default_configs,
dimensions: self.dimensions,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -n 'fn filter_by_eval' --type rust -A 5

Repository: juspay/superposition

Length of output: 1026


Remove unnecessary clone of self.contexts.

The filter_by_eval method accepts Vec<Self> by value (not by reference), so self.contexts can be passed directly without cloning:

let filtered_context = Context::filter_by_eval(self.contexts, &modified_context);

Since self is consumed and self.contexts is not used afterward, the clone is avoidable.

🤖 Prompt for AI Agents
In `@crates/superposition_types/src/config.rs` around lines 292 - 317, In
filter_by_dimensions, remove the unnecessary clone of self.contexts and pass
ownership directly to Context::filter_by_eval (i.e., call
Context::filter_by_eval(self.contexts, &modified_context)) since
filter_by_dimensions consumes self and contexts is not used afterward; update
the call site in the function where filtered_context is created (referencing
Context::filter_by_eval and self.contexts) so you avoid the clone and retain the
existing use of self.overrides via let mut overrides = self.overrides.

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.

1 participant

Comments