Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
5bc3e15
new macros wip
akashsoni01 Nov 5, 2025
8f351b4
wip
akashsoni01 Nov 5, 2025
4170e42
methods added for option
akashsoni01 Nov 5, 2025
144d909
single type added
akashsoni01 Nov 5, 2025
233d52b
wip
akashsoni01 Nov 5, 2025
6f3eaef
fail optimized
akashsoni01 Nov 5, 2025
5440e3f
wip
akashsoni01 Nov 5, 2025
2c1354a
it wip
akashsoni01 Nov 7, 2025
25be6c4
wip
akashsoni01 Nov 7, 2025
0d63753
wip
akashsoni01 Nov 7, 2025
3760581
struct level added
akashsoni01 Nov 8, 2025
c2893c1
default set to readable
akashsoni01 Nov 8, 2025
571aea8
all attribute added
akashsoni01 Nov 8, 2025
7972953
more container support added
akashsoni01 Nov 8, 2025
a98392d
ver
akashsoni01 Nov 8, 2025
a3baf99
example updated
akashsoni01 Nov 8, 2025
a038a00
readme updated
akashsoni01 Nov 8, 2025
db18fdf
version updated
akashsoni01 Nov 23, 2025
dbc7d3c
wip
akashsoni01 Nov 23, 2025
3d597c8
benches of current version
akashsoni01 Nov 23, 2025
cf6bc4a
wip
akashsoni01 Nov 23, 2025
bc430b7
wip
akashsoni01 Nov 23, 2025
199be9f
performance opti wip
akashsoni01 Nov 23, 2025
421a5bc
arc opti to rc
akashsoni01 Nov 23, 2025
ad8baf3
wip
akashsoni01 Nov 23, 2025
561af0b
read optimisation
akashsoni01 Nov 23, 2025
131146a
versioning
akashsoni01 Nov 23, 2025
5ffdd45
bench updated
akashsoni01 Nov 29, 2025
3382c14
trait orint wip
akashsoni01 Dec 5, 2025
c1cd7ab
Merge branch 'codefonsi:main' into main
akashsoni01 Dec 6, 2025
6eff81d
Merge branch 'main' of https://github.com/akashsoni01/rust-key-paths
akashsoni01 Dec 6, 2025
f630a14
wip
akashsoni01 Dec 6, 2025
a094821
wip
akashsoni01 Dec 6, 2025
09d11d9
wip
akashsoni01 Dec 6, 2025
28e3930
wip eg
akashsoni01 Dec 6, 2025
74d97f2
appending operator added
akashsoni01 Dec 6, 2025
44693ec
wip running eg
akashsoni01 Dec 6, 2025
5639bf4
wip
akashsoni01 Dec 6, 2025
6896996
for box added
akashsoni01 Dec 6, 2025
68be650
wp
akashsoni01 Dec 6, 2025
4c29bbe
wip
akashsoni01 Dec 6, 2025
0ed02e7
wip
akashsoni01 Dec 6, 2025
130c140
memory release and clone tested
akashsoni01 Dec 6, 2025
2043376
benches
akashsoni01 Dec 6, 2025
5351edc
readme updated
akashsoni01 Dec 6, 2025
2890bab
code cleaning
akashsoni01 Dec 6, 2025
2497aa5
collection support added
akashsoni01 Dec 6, 2025
181f85e
option added
akashsoni01 Dec 6, 2025
be47a44
writable added
akashsoni01 Dec 6, 2025
1d52480
wip
akashsoni01 Dec 6, 2025
21c6dd0
locks wip
akashsoni01 Dec 6, 2025
232fc3a
any and partial wip
akashsoni01 Dec 6, 2025
5cec716
partial and any working eg
akashsoni01 Dec 6, 2025
8686cde
eg added
akashsoni01 Dec 6, 2025
15e3160
wip
akashsoni01 Dec 6, 2025
877f95d
benchmark report updated
akashsoni01 Dec 6, 2025
9655f5e
ver
akashsoni01 Dec 6, 2025
bac380d
migration wip
akashsoni01 Dec 6, 2025
b258979
ver and migration guid
akashsoni01 Dec 6, 2025
f100533
wip
akashsoni01 Dec 6, 2025
9ddded8
ver
akashsoni01 Dec 6, 2025
13e2bec
eg wip
akashsoni01 Dec 6, 2025
035985f
casepath working for writing
akashsoni01 Dec 6, 2025
b9772bf
basic macros eg
akashsoni01 Dec 6, 2025
ba29ba4
box working
akashsoni01 Dec 6, 2025
8207200
change tracker eg fixed
akashsoni01 Dec 6, 2025
8ba16ba
wip
akashsoni01 Dec 6, 2025
7a90963
helper method wip
akashsoni01 Dec 7, 2025
697e263
wip
akashsoni01 Dec 7, 2025
96fdb12
wip
akashsoni01 Dec 7, 2025
2679088
wip
akashsoni01 Dec 7, 2025
3dc42c2
macro wip
akashsoni01 Dec 7, 2025
c4bf7a1
wip
akashsoni01 Dec 7, 2025
2dd887a
unused import removed
akashsoni01 Dec 7, 2025
0cde32c
tagged support added
akashsoni01 Dec 7, 2025
2cb24ff
compri eg fixed
akashsoni01 Dec 7, 2025
916286b
cat fixed
akashsoni01 Dec 7, 2025
aaefdff
ca working
akashsoni01 Dec 7, 2025
be3abf3
dnc working
akashsoni01 Dec 7, 2025
aa23cd6
drce working
akashsoni01 Dec 7, 2025
6428009
dmnfe working
akashsoni01 Dec 7, 2025
ff02be8
ecm working
akashsoni01 Dec 7, 2025
87e0621
wip
akashsoni01 Dec 7, 2025
ec12847
enum keypath wip
akashsoni01 Dec 7, 2025
e2c6249
cp working
akashsoni01 Dec 7, 2025
b898a84
wip
akashsoni01 Dec 7, 2025
4806590
integration_test working
akashsoni01 Dec 7, 2025
e3acd3c
bench wip
akashsoni01 Dec 7, 2025
cadf960
readme updated
akashsoni01 Dec 7, 2025
0d93c50
complex macros working
akashsoni01 Dec 10, 2025
13a0acf
docs wip
akashsoni01 Dec 10, 2025
7e693ae
ekm working
akashsoni01 Dec 10, 2025
23ac9de
failable combined kp added
akashsoni01 Dec 10, 2025
bef8190
fm working
akashsoni01 Dec 10, 2025
5aabb5d
combined operator
akashsoni01 Dec 10, 2025
40bf689
ver
akashsoni01 Dec 10, 2025
4350e9c
fw eg working
akashsoni01 Dec 11, 2025
a32ef94
fw working
akashsoni01 Dec 11, 2025
eae865a
to option added
akashsoni01 Dec 11, 2025
b262b95
hashmap working
akashsoni01 Dec 11, 2025
4a5f6d1
ver
akashsoni01 Dec 11, 2025
6fd7267
form binding working
akashsoni01 Dec 15, 2025
79b4fac
iter working
akashsoni01 Dec 15, 2025
b143e4b
query builder example
akashsoni01 Dec 15, 2025
503b6e2
join query
akashsoni01 Dec 15, 2025
346c9c4
simple enum
akashsoni01 Dec 15, 2025
b35a47e
ket working
akashsoni01 Dec 15, 2025
a02b2c8
working
akashsoni01 Dec 15, 2025
984fadb
wip
akashsoni01 Dec 15, 2025
c656444
back to kp from optkp
akashsoni01 Dec 15, 2025
48856ef
kp wip
akashsoni01 Dec 15, 2025
5f9ec4c
wip
akashsoni01 Dec 15, 2025
7203095
nested types
akashsoni01 Dec 15, 2025
77daba4
ver
akashsoni01 Dec 15, 2025
236444e
partial kp type infer
akashsoni01 Dec 16, 2025
3362e46
Backword compatibility
akashsoni01 Dec 16, 2025
30bdc49
extract_from_slice
akashsoni01 Dec 16, 2025
3d72ddf
qb working
akashsoni01 Dec 16, 2025
6aebec5
ver
akashsoni01 Dec 16, 2025
0bde3f1
bench wip
akashsoni01 Dec 16, 2025
9fec435
wip
akashsoni01 Dec 16, 2025
01259de
benches updated
akashsoni01 Dec 16, 2025
7a1d720
lock kp wip
akashsoni01 Dec 17, 2025
37df20a
wip
akashsoni01 Dec 17, 2025
b59a461
closure removed for update
akashsoni01 Dec 17, 2025
10d6f4b
lib comp
akashsoni01 Dec 17, 2025
4d39110
Revert "lib comp"
akashsoni01 Dec 17, 2025
4c5455c
tuple eg updated
akashsoni01 Dec 17, 2025
1efefde
shr wip
akashsoni01 Dec 17, 2025
913de0a
+ operator added
akashsoni01 Dec 17, 2025
acd5e1d
wip
akashsoni01 Dec 17, 2025
e1bb6d3
using prior art of shr operator
akashsoni01 Dec 17, 2025
0296862
ver
akashsoni01 Dec 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions CASEPATHS_ENHANCEMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Casepaths Macro Enhancement

## Overview

The `Casepaths` derive macro has been updated to work with the new `rust-keypaths` API, providing automatic generation of enum variant keypaths.

## Generated Methods

For each enum variant, the macro generates:

### Single-Field Variants
```rust
enum MyEnum {
Variant(InnerType),
}

// Generated methods:
MyEnum::variant_case_fr() -> OptionalKeyPath<MyEnum, InnerType, ...>
MyEnum::variant_case_fw() -> WritableOptionalKeyPath<MyEnum, InnerType, ...>
```

### Multi-Field Tuple Variants
```rust
enum MyEnum {
Variant(T1, T2, T3),
}

// Generated methods:
MyEnum::variant_case_fr() -> OptionalKeyPath<MyEnum, (T1, T2, T3), ...>
MyEnum::variant_case_fw() -> WritableOptionalKeyPath<MyEnum, (T1, T2, T3), ...>
```

### Named Field Variants
```rust
enum MyEnum {
Variant { field1: T1, field2: T2 },
}

// Generated methods:
MyEnum::variant_case_fr() -> OptionalKeyPath<MyEnum, (T1, T2), ...>
MyEnum::variant_case_fw() -> WritableOptionalKeyPath<MyEnum, (T1, T2), ...>
```

### Unit Variants
```rust
enum MyEnum {
Variant,
}

// Generated methods:
MyEnum::variant_case_fr() -> OptionalKeyPath<MyEnum, (), ...>
```

## Attribute Support

The macro supports the same attributes as `Keypaths`:

- `#[Readable]` - Generate only readable methods (`_case_fr()`)
- `#[Writable]` - Generate only writable methods (`_case_fw()`)
- `#[All]` - Generate both readable and writable methods (default)

### Example

```rust
#[derive(Casepaths)]
#[Writable] // Generate only writable methods
enum MyEnum {
A(String),
B(Box<InnerStruct>),
}

// Usage:
let path = MyEnum::b_case_fw() // Returns WritableOptionalKeyPath
.for_box() // Unwrap Box<InnerStruct>
.then(InnerStruct::field_fw());
```

## Key Features

1. **Type Safety**: Returns `OptionalKeyPath`/`WritableOptionalKeyPath` since variant extraction may fail
2. **Container Support**: Works seamlessly with `Box<T>`, `Arc<T>`, `Rc<T>` via `.for_box()`, `.for_arc()`, `.for_rc()`
3. **Chaining**: Can be chained with `.then()` for nested access
4. **Attribute-Based Control**: Use `#[Readable]`, `#[Writable]`, or `#[All]` to control which methods are generated

## Migration from Old API

### Old API (key-paths-core)
```rust
#[derive(Casepaths)]
enum MyEnum {
Variant(InnerType),
}

// Generated methods returned KeyPaths enum
let path = MyEnum::variant_case_r();
```

### New API (rust-keypaths)
```rust
#[derive(Casepaths)]
#[Writable]
enum MyEnum {
Variant(InnerType),
}

// Generated methods return specific types
let path = MyEnum::variant_case_fw(); // Returns WritableOptionalKeyPath
```

## Example: Deep Nesting with Box

```rust
#[derive(Keypaths)]
#[Writable]
struct Outer {
inner: Option<MyEnum>,
}

#[derive(Casepaths)]
#[Writable]
enum MyEnum {
B(Box<InnerStruct>),
}

#[derive(Keypaths)]
#[Writable]
struct InnerStruct {
field: Option<String>,
}

// Chain through Option -> Enum variant -> Box -> Option
let path = Outer::inner_fw()
.then(MyEnum::b_case_fw()) // Extract variant
.for_box() // Unwrap Box
.then(InnerStruct::field_fw());

// Use it
if let Some(value) = path.get_mut(&mut instance) {
*value = "new value".to_string();
}
```

## Implementation Details

- **Variant Extraction**: Uses pattern matching to safely extract variant values
- **Type Inference**: Automatically handles all variant field types
- **Error Handling**: Returns `None` if the enum is not the expected variant
- **Zero-Cost**: Compiles to direct pattern matching, no runtime overhead

45 changes: 33 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[package]
name = "rust-key-paths"
version = "1.8.0"
version = "1.11.5"
edition = "2024"
authors = ["Codefonsi <[email protected]>"]
license = "MPL-2.0"
description = "Keypaths, ReadableKeyPath, WritableKeyPath and EnumKeypath for struct and enums in Rust."
description = "Keypaths for Rust: Static dispatch implementation (rust-keypaths) and legacy dynamic dispatch (key-paths-core). Type-safe, composable access to nested data structures."
repository = "https://github.com/codefonsi/rust-key-paths"
homepage = "https://github.com/codefonsi/rust-key-paths"
documentation = "https://docs.rs/rust-key-paths"
Expand All @@ -13,30 +13,51 @@ readme = "./README.md"
include = ["src/**/*", "Cargo.toml", "../../README.md", "LICENSE"]

[dependencies]
key-paths-core = { path = "key-paths-core", version = "1.6.0", features = ["tagged_core"] }
key-paths-derive = { path = "key-paths-derive", version = "1.0.8"}
# Primary crates: rust-keypaths (static dispatch, faster) and keypaths-proc (proc macros)
rust-keypaths = "1.0.7"
keypaths-proc = "1.0.6"

# Legacy crates: key-paths-core 1.6.0 for dynamic dispatch, multithreaded needs
# Note: Use key-paths-core = "1.6.0" if you need dynamic dispatch or Send + Sync bounds
# key-paths-core = { path = "key-paths-core", version = "1.6.0", features = ["tagged_core"] }
# key-paths-derive = { path = "key-paths-derive", version = "1.1.0"}


[workspace]
resolver = "3" # or "3"
members = [
"rust-keypaths",
"keypaths-proc",
# Legacy members (kept for backward compatibility)
"key-paths-core",
"key-paths-derive"
]
"key-paths-derive",
"key-paths-macros"
, "keypaths-core"]

[patch.crates-io]
key-paths-core = { path = "key-paths-core" }
key-paths-derive = { path = "key-paths-derive" }

# key-paths-core = { path = "key-paths-core" }
# key-paths-derive = { path = "key-paths-derive" }
rust-keypaths = { path = "rust-keypaths" }
keypaths-proc = { path = "keypaths-proc" }
[features]
default = []
parking_lot = ["key-paths-core/parking_lot"]
tagged_core = ["key-paths-core/tagged_core"]
# Features for rust-keypaths (static dispatch)
parking_lot = ["rust-keypaths/parking_lot"]
tagged = ["rust-keypaths/tagged"]
nightly = ["rust-keypaths/nightly"]
# Legacy features for key-paths-core (dynamic dispatch)
# parking_lot_legacy = ["key-paths-core/parking_lot"]
# tagged_core = ["key-paths-core/tagged_core"]

[dev-dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
parking_lot = "0.12"
tagged-core = "0.7.0"
tagged-core = "0.8.0"
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1.0", features = ["v4", "serde"] }
criterion = { version = "0.5", features = ["html_reports"] }

[[bench]]
name = "keypath_vs_unwrap"
harness = false
113 changes: 113 additions & 0 deletions EXAMPLES_FIXES_FINAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Examples Fixes - Final Status

## ✅ Completed Enhancements to rust-keypaths

### 1. Added `to_optional()` Methods
- **KeyPath::to_optional()** - Converts `KeyPath` to `OptionalKeyPath` for chaining
- **WritableKeyPath::to_optional()** - Converts `WritableKeyPath` to `WritableOptionalKeyPath` for chaining

### 2. Added Container Adapter Methods
- **OptionalKeyPath::with_option()** - Execute closure with value inside `Option<T>`
- **OptionalKeyPath::with_mutex()** - Execute closure with value inside `Mutex<T>`
- **OptionalKeyPath::with_rwlock()** - Execute closure with value inside `RwLock<T>`
- **OptionalKeyPath::with_arc_rwlock()** - Execute closure with value inside `Arc<RwLock<T>>`
- **OptionalKeyPath::with_arc_mutex()** - Execute closure with value inside `Arc<Mutex<T>>`
- **KeyPath::with_arc_rwlock_direct()** - Direct support for `Arc<RwLock<T>>`
- **KeyPath::with_arc_mutex_direct()** - Direct support for `Arc<Mutex<T>>`

### 3. Added `get()` to WritableKeyPath
- **WritableKeyPath::get()** - Returns `&Value` (requires `&mut Root`)
- Note: For optional fields, use `WritableOptionalKeyPath::get_mut()` which returns `Option<&mut Value>`

## 📊 Current Status

- ✅ **rust-keypaths library**: Compiles successfully
- ✅ **keypaths-proc macro**: Compiles successfully
- ⚠️ **Examples**: ~41 errors remaining (down from 131)

## 🔧 Remaining Issues

### 1. Type Mismatches (29 errors)
- **Issue**: Examples expect `WritableKeyPath::get()` to return `Option<&mut Value>`
- **Reality**: `WritableKeyPath::get()` returns `&Value` (non-optional)
- **Solution**: Examples should use:
- `WritableOptionalKeyPath::get_mut()` for optional fields
- Or convert using `.to_optional()` first

### 2. Missing Methods (9 errors)
- `with_arc_rwlock_direct` / `with_arc_mutex_direct` - ✅ **FIXED** (just added)
- `extract_from_slice` - May need to be added if used in examples

### 3. Clone Issues (2 errors)
- Some `KeyPath` instances don't satisfy `Clone` bounds
- This happens when the closure type doesn't implement `Clone`
- **Solution**: Use `.clone()` only when the keypath is from derive macros (which generate Clone-able closures)

### 4. Other Issues (1 error)
- `Option<&mut T>` cannot be dereferenced - Need to use `if let Some(x) = ...` pattern
- Missing `main` function in one example

## 🎯 Next Steps

1. **Fix WritableKeyPath usage**: Update examples to use `WritableOptionalKeyPath` for optional fields
2. **Add missing methods**: Add `extract_from_slice` if needed
3. **Fix type mismatches**: Update examples to match the actual API
4. **Test all examples**: Run each example to verify it works correctly

## 📝 API Summary

### KeyPath API
```rust
// Direct access (non-optional)
let kp = KeyPath::new(|r: &Root| &r.field);
let value = kp.get(&root); // Returns &Value

// Convert to optional for chaining
let opt_kp = kp.to_optional(); // Returns OptionalKeyPath
let value = opt_kp.get(&root); // Returns Option<&Value>

// Container adapters
kp.with_option(&opt, |v| ...);
kp.with_mutex(&mutex, |v| ...);
kp.with_rwlock(&rwlock, |v| ...);
kp.with_arc_rwlock_direct(&arc_rwlock, |v| ...);
```

### WritableKeyPath API
```rust
// Direct mutable access (non-optional)
let wk = WritableKeyPath::new(|r: &mut Root| &mut r.field);
let value = wk.get_mut(&mut root); // Returns &mut Value
let value_ref = wk.get(&mut root); // Returns &Value

// Convert to optional for chaining
let opt_wk = wk.to_optional(); // Returns WritableOptionalKeyPath
```

### OptionalKeyPath API
```rust
// Failable access
let okp = OptionalKeyPath::new(|r: &Root| r.field.as_ref());
let value = okp.get(&root); // Returns Option<&Value>

// Chaining
let chained = okp.then(other_okp);

// Container adapters
okp.with_option(&opt, |v| ...);
okp.with_mutex(&mutex, |v| ...);
okp.with_rwlock(&rwlock, |v| ...);
```

## 🚀 Migration Notes

When migrating from `key-paths-core` to `rust-keypaths`:

1. **KeyPaths enum** → Use specific types (`KeyPath`, `OptionalKeyPath`, etc.)
2. **KeyPaths::readable()** → `KeyPath::new()`
3. **KeyPaths::failable_readable()** → `OptionalKeyPath::new()`
4. **.compose()** → `.then()` (only on `OptionalKeyPath`)
5. **WithContainer trait** → Use `with_*` methods directly on keypaths
6. **KeyPath.get()** → Returns `&Value` (not `Option`)
7. **WritableKeyPath.get_mut()** → Returns `&mut Value` (not `Option`)

Loading