Skip to content

Commit f0fe238

Browse files
aepfliclaude
andauthored
docs: update README to reflect instance-based API refactoring (#53)
Updated documentation to match the new architecture: - Features: Replaced "Flag State Management" with "Instance-Based API" and added "Type-Specific Evaluation" to highlight new capabilities - Rust Usage: Completely rewrote example to use FlagEvaluator instead of deleted storage module and evaluation functions - API Reference: Added type-specific evaluation functions (evaluate_boolean, evaluate_string, evaluate_integer, evaluate_float, evaluate_object) - Validation Modes: Updated to show per-instance validation mode instead of global storage module approach All examples now accurately reflect the current codebase after the storage module removal and FlagEvaluator refactoring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Description <!-- Provide a brief description of your changes --> ## Related Issue <!-- Link to the related issue(s) --> Closes # ## Type of Change <!-- Mark the relevant option with an "x" --> - [ ] `feat`: New feature (minor version bump) - [ ] `fix`: Bug fix (patch version bump) - [ ] `docs`: Documentation only changes - [ ] `chore`: Maintenance tasks, dependency updates - [ ] `refactor`: Code refactoring without functional changes - [ ] `test`: Adding or updating tests - [ ] `ci`: CI/CD changes - [ ] `perf`: Performance improvements - [ ] `build`: Build system changes - [ ] `style`: Code style/formatting changes ## PR Title Format **IMPORTANT**: Since we use squash and merge, your PR title will become the commit message. Please ensure your PR title follows the [Conventional Commits](https://www.conventionalcommits.org/) format: ``` <type>(<optional-scope>): <description> ``` ### Examples: - `feat(operators): add new string comparison operator` - `fix(wasm): correct memory allocation bug` - `docs: update API examples in README` - `chore(deps): update rust dependencies` For breaking changes, use `!` after the type/scope or include `BREAKING CHANGE:` in the PR description: - `feat(api)!: redesign evaluation API` ## Testing <!-- Describe the testing you've performed --> - [ ] Unit tests added/updated - [ ] Integration tests added/updated - [ ] Manual testing performed - [ ] All tests pass (`cargo test`) - [ ] Code is formatted (`cargo fmt`) - [ ] Clippy checks pass (`cargo clippy -- -D warnings`) - [ ] WASM builds successfully (if applicable) ## Breaking Changes <!-- If this introduces breaking changes, describe them here --> - [ ] This PR includes breaking changes - [ ] Documentation has been updated to reflect breaking changes - [ ] Migration guide included (if needed) ## Additional Notes <!-- Any additional information, context, or screenshots --> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 948adcd commit f0fe238

1 file changed

Lines changed: 60 additions & 22 deletions

File tree

README.md

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ A WebAssembly-based JSON Logic evaluator with custom operators for feature flag
1010
- **Full JSON Logic Support**: Evaluate complex JSON Logic rules with all standard operators via [datalogic-rs](https://github.com/cozylogic/datalogic-rs)
1111
- **Custom Operators**: Feature-flag specific operators like `fractional` for A/B testing
1212
- **JSON Schema Validation**: Validates flag configurations against the official [flagd-schemas](https://github.com/open-feature/flagd-schemas)
13-
- **Configurable Validation Mode**: Choose between strict (reject invalid configs) or permissive (store with warnings) validation
14-
- **Flag State Management**: Internal storage for flag configurations with `update_state` API
13+
- **Configurable Validation Mode**: Choose between strict (reject invalid configs) or permissive (store with warnings) validation per evaluator instance
14+
- **Instance-Based API**: Use `FlagEvaluator` for stateful flag evaluation in Rust, or singleton WASM exports for language interop
15+
- **Type-Specific Evaluation**: Dedicated functions for boolean, string, integer, float, and object flags with type checking
1516
- **Chicory Compatible**: Works seamlessly with pure Java WASM runtimes - no JNI required
1617
- **Zero Dependencies at Runtime**: Single WASM file, no external dependencies
1718
- **Optimized Size**: WASM binary optimized for size (~2.4MB, includes full JSON Logic implementation and schema validation)
@@ -464,42 +465,70 @@ See [GitHub issue #48](https://github.com/open-feature-forking/flagd-evaluator/i
464465

465466
### Rust
466467

468+
The Rust library provides an instance-based `FlagEvaluator` API for stateful flag evaluation:
469+
467470
```rust
468-
use flagd_evaluator::evaluation::{evaluate_flag, EvaluationContext};
469-
use flagd_evaluator::model::FlagConfiguration;
471+
use flagd_evaluator::{FlagEvaluator, ValidationMode};
470472
use serde_json::json;
471473

472-
// Parse flag configuration
473-
let config_json = json!({
474+
// Create evaluator with strict validation (default)
475+
let mut evaluator = FlagEvaluator::new(ValidationMode::Strict);
476+
477+
// Update flag configuration
478+
let config = json!({
474479
"flags": {
475480
"myFlag": {
476481
"state": "ENABLED",
477482
"variants": {"on": true, "off": false},
478-
"defaultVariant": "on"
483+
"defaultVariant": "on",
484+
"targeting": {
485+
"if": [
486+
{"==": [{"var": "email"}, "admin@example.com"]},
487+
"on",
488+
"off"
489+
]
490+
}
479491
}
480492
}
481-
});
493+
}).to_string();
482494

483-
let config: FlagConfiguration = serde_json::from_value(config_json).unwrap();
495+
evaluator.update_state(&config).unwrap();
484496

485-
// Store the configuration (in real usage, use storage module)
486-
// For this example, we'll evaluate directly
487-
let flag = config.flags.get("myFlag").unwrap();
488-
let context = EvaluationContext::default();
497+
// Evaluate with type-specific methods
498+
let result = evaluator.evaluate_bool("myFlag", &json!({}));
499+
println!("{:?}", result.value); // false (default variant)
489500

490-
let result = evaluate_flag("myFlag", flag, &context);
491-
println!("{:?}", result.value);
492-
// Output: true
501+
let result = evaluator.evaluate_bool("myFlag", &json!({"email": "admin@example.com"}));
502+
println!("{:?}", result.value); // true (targeting matched)
503+
504+
// Or use the generic evaluate method for full result details
505+
let result = evaluator.evaluate_flag("myFlag", &json!({}));
506+
println!("Variant: {:?}, Reason: {:?}", result.variant, result.reason);
493507
```
494508

509+
**Type-Specific Evaluation Methods:**
510+
- `evaluate_bool(flag_key, context) -> EvaluationResult` - For boolean flags
511+
- `evaluate_string(flag_key, context) -> EvaluationResult` - For string flags
512+
- `evaluate_int(flag_key, context) -> EvaluationResult` - For integer flags
513+
- `evaluate_float(flag_key, context) -> EvaluationResult` - For float flags
514+
- `evaluate_object(flag_key, context) -> EvaluationResult` - For object flags
515+
- `evaluate_flag(flag_key, context) -> EvaluationResult` - Generic evaluation
516+
517+
Each evaluator instance maintains its own flag configuration state and validation mode.
518+
495519
## API Reference
496520

497521
### Exported Functions
498522

499523
| Function | Signature | Description |
500524
|----------|-----------|-------------|
501525
| `update_state` | `(config_ptr, config_len) -> u64` | Updates the feature flag configuration state |
502-
| `evaluate` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates a feature flag against context |
526+
| `evaluate` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates a feature flag against context (generic) |
527+
| `evaluate_boolean` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates a boolean flag with type checking |
528+
| `evaluate_string` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates a string flag with type checking |
529+
| `evaluate_integer` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates an integer flag with type checking |
530+
| `evaluate_float` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates a float flag with type checking |
531+
| `evaluate_object` | `(flag_key_ptr, flag_key_len, context_ptr, context_len) -> u64` | Evaluates an object flag with type checking |
503532
| `set_validation_mode` | `(mode: u32) -> u64` | Sets validation mode (0=Strict, 1=Permissive) |
504533
| `alloc` | `(len: u32) -> *mut u8` | Allocates memory in WASM linear memory |
505534
| `dealloc` | `(ptr: *mut u8, len: u32)` | Frees previously allocated memory |
@@ -831,17 +860,26 @@ You can configure how validation errors are handled:
831860
- **Permissive Mode**: Stores flag configurations even if validation fails (useful for legacy configurations)
832861

833862
**From Rust:**
863+
864+
Each `FlagEvaluator` instance can have its own validation mode:
865+
834866
```rust
835-
use flagd_evaluator::storage::{set_validation_mode, ValidationMode};
867+
use flagd_evaluator::{FlagEvaluator, ValidationMode};
836868

837-
// Use strict validation (default)
838-
set_validation_mode(ValidationMode::Strict);
869+
// Create evaluator with strict validation (default)
870+
let strict_evaluator = FlagEvaluator::new(ValidationMode::Strict);
839871

840-
// Use permissive validation
841-
set_validation_mode(ValidationMode::Permissive);
872+
// Create evaluator with permissive validation
873+
let permissive_evaluator = FlagEvaluator::new(ValidationMode::Permissive);
874+
875+
// Change validation mode on an existing evaluator
876+
let mut evaluator = FlagEvaluator::new(ValidationMode::Strict);
877+
evaluator.set_validation_mode(ValidationMode::Permissive);
842878
```
843879

844880
**From WASM (e.g., Java via Chicory):**
881+
882+
The WASM module uses a singleton evaluator, and you can set its validation mode globally:
845883
```java
846884
// Get the set_validation_mode function
847885
WasmFunction setValidationMode = instance.export("set_validation_mode");

0 commit comments

Comments
 (0)