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::*;

Modules

optics

definitions of optics (including derived optic)

traits

definitions of optics traits

Macros

Optics

macro to compose optics

optics

macro to compose optics

Structs

_0

build-in optics

_1

build-in optics

_2

build-in optics

_3

build-in optics

_4

build-in optics

_5

build-in optics

_6

build-in optics

_7

build-in optics

_8

build-in optics

_9

build-in optics

_10

build-in optics

_11

build-in optics

_12

build-in optics

_13

build-in optics

_14

build-in optics

_15

build-in optics

_16

build-in optics

__

build-in optics

_both

build-in optics

_box

build-in optics

_ix

build-in optics

_mapped

build-in optics

_mut

build-in optics

_ref

build-in 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

Prism

derive macro

Review

derive macro