Crate lens_rs[][src]

Overview

lens-rs is a lens library for Rust, just like the package lens for Haskell, but here are no weird operators, grotesque symbols and confusing types. Not only can lens-rs get/set for fields of struct, but also variants of enum and items of collection. It unifies the way to access to/construct with different nested substructures, providing Rusty-APIs.

Before use

Add the following in your Cargo.toml

[dependencies]
lens-rs = "0.2"

[package.metadata.inwelling]
lens-rs = true

Add the following in your .rs files

use lens_rs::*;

Usage

Access substructures

visit field in struct:

let mut x = Foo { a: String::from(".a in Foo"), b: 0 };
assert_eq!(x.view_ref(optics!(a)), ".a in Foo");

*x.view_mut(optics!(b)) += 1;
assert_eq!(x.view_ref(optics!(b)), &1)

visit variant in enum:

let mut x = Ok(0);
*x.preview_ref(optics!(Ok))? += 1;
assert_eq!(x.preview_ref(optics!(Ok))?, &1);
assert_eq!(x.preview_ref(optics!(Err)), None);

visit items in collection:

let mut x = vec![1, 2, 3];
x.traverse_mut(optics!(_mapped)).into_iter().for_each(|x| *x += 1);
assert_eq!(x.traverse_ref(optics!(_mapped)), vec![&2, &3, &4]);
assert_eq!(x.view_ref(optics!([1])), &3);

build a structure:

let x = Review::review(optics!(Ok.Some), 1);
assert_eq!(x, Ok(Some(1)));

Compose optics

macro optics!() and Optics![] is to compose optics:

let optics: Optics![_1.a.Some._mapped.[1]] = optics!(_1.a.Some._mapped.[1]);

let x = (0, Foo {
    a: Some(vec![vec![1,2], vec![3,4]]),
    b: ()
});

assert_eq!(x.traverse(optics), vec![2, 4]);

Derive Optics

Derive Lens for fields to use .view_xx(). (derive(Optic) is necessary)

#[derive(Optic, Lens)]
struct Foo<A, B> {
    #[optic]
    a: A, // generate optics::a
    #[optic]
    b: B, // generate optics::b
}

#[derive(Optic, Lens)]
struct Tuple<A, B>(#[optic] A, #[optic] B);
// use optics::_0 or optics::_1 to access it

Derive Review/Prism for variants to use Review::review/.preview_xx():

#[derive(Optic, Review, Prism)]
enum Either<L, R> {
    #[optic]
    Left(L), // generate optics::Left
    #[optic]
    Right(R), // generate optics::Right
}

Control the mutability:

#[derive(Debug, Optic, Lens)]
struct Bar<C>{
    #[optic(ref)]
    a: String,    // can only take the immutable ref of .a by optics::a
    #[optic(mut)]
    b: i32,       // can take the mutable ref of .b by optics::b
    #[optic]
    c: C          // can move .c out by by optics::c
}

A little row polymorphism

restrict a type has some fields:

fn with_field_a<T>(t: &T) -> &str
where
    T: LensRef<Optics![a], Image = String>, // T must have field a
{
    t.view_ref(optics!(a))
}


let foo = Foo {
    a: "this is Foo".to_string(),
    b: (),
};
let bar = Bar {
    a: "this is Bar".to_string(),
    c: 0,
};

assert_eq!(with_field_a(&foo), "this is Foo");
assert_eq!(with_field_a(&bar), "this is Bar");

Limitations

  • can’t derive Lens for enum.
  • can’t derive Prism and Review for the variant has more than one argument or has named field.

License

Under Apache License 2.0 or MIT License, at your will.

Re-exports

pub use traits::prism::*;
pub use traits::review::*;
pub use traits::traversal::*;
pub use traits::Optic;
pub use optics::_both;
pub use optics::_box;
pub use optics::_ix;
pub use optics::_mapped;
pub use optics::_mut;
pub use optics::_ref;
pub use optics::_0;
pub use optics::_1;
pub use optics::_2;
pub use optics::_3;
pub use optics::_4;
pub use optics::_5;
pub use optics::_6;
pub use optics::__;

Modules

optics

definitions of optics (including derived optic)

traits

definitions of optics traits

Macros

Optics

macro to compose optics

optics

macro to compose optics

Traits

Lens

the movable version of Lens

LensMut

the mutable version of Lens

LensRef

the immutable version of Lens

Derive Macros

Lens

derive macro

Optic

derive macro

Prism

derive macro

Review

derive macro