3 unstable releases

0.2.0 Jun 25, 2021
0.1.1 Jun 18, 2021
0.1.0 Jun 15, 2021

#2480 in Rust patterns


Used in keypath-proc-macros

Apache-2.0

24KB
561 lines

keypath

Strongly typed references to arbitrarily nested fields.

This is an early experiment in implementing Swift-style keypaths in Rust. It is currently intended as a proof of concept, and is missing some fancier features such as 'partial keypaths' and composibility, although implementing these should not be especially challanging. What this does include is what I believe is the most difficult case, of generating typed keypaths for arbitrary types that are guaranteed at compile time.

This means you can do the following:

#[derive(Keyable)]
struct Person {
    name: String,
    friends: Vec<String>,
    size: Size,
}
#[derive(Keyable)]
struct Size {
    big: bool,
    heft: u8,
}

let mut person = Person {
    name: "coco".into(),
    friends: vec!["eli".into(), "nico".into(), "yaya".into()],
    size: Size { big: false, heft: 45 }
};

let first_friend: KeyPath<Person, String> = keypath!(Person.friends[0]);
let heft = keypath!(Person.size.heft);

assert_eq!(person[&first_friend], "eli");

// mutation:
person[&heft] = 101;
assert_eq!(person.size.heft, 101);

This may not seem especially useful on its own, but it is an ergonomic building block for things like UI bindings, and observable objects.

todos

There are a bunch of additional features and ideas that would be worth exploring, here:

  • allow collection access to return optionals, with chaining: People.friends[10]?.age would allow the indexing operation to fail.
  • easier implementation for collections (currently manual, no derive available)
  • support for generics in the keypath! macro

Dependencies

~1.5MB
~40K SLoC