1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! A lens describes a view into a data structure, like an index or key lookup,
//! with the ability to modify what it sees. It provides a get operation (get
//! the thing we're a lens for) and a set operation (modify the data structure
//! we're a lens into with the a value for the thing).
//!
//! Lenses are composable, so that if you have a lens from A to a thing B inside
//! A, and you have a lens from B to another thing C inside B, you can compose
//! them to make a lens from A directly into C.
//!
//! There are two kinds of lenses defined here: `PartialLens`, which is a lens
//! into something which doesn't necessarily exist (such as a map key), and
//! `Lens`, which must always be able to succeed. All `Lens`es are also
//! `PartialLens`es, but the opposite is not true.

use std::marker::PhantomData;
use std::sync::Arc;

/// A lens from `From` to `To` where the focus of the lens isn't guaranteed to
/// exist inside `From`. Operations on these lenses therefore return `Option`s.
pub trait PartialLens: Clone {
    type From;
    type To;

    /// Get the focus of the lens, if available.
    fn try_get<R>(&self, s: R) -> Option<Arc<Self::To>>
    where
        R: AsRef<Self::From>;

    /// Put a value into the lens, returning the updated `From` value is the
    /// operation succeeded.
    fn try_put<Convert, R>(&self, v: Option<Convert>, s: R) -> Option<Self::From>
    where
        R: AsRef<Self::From>,
        Arc<Self::To>: From<Convert>;

    /// Compose this lens with a lens from `To` to a new type `Next`, yielding
    /// a lens from `From` to `Next`.
    fn try_chain<L, Next>(&self, next: &L) -> Compose<Self::From, Self::To, Next, Self, L>
    where
        L: PartialLens<From = Self::To, To = Next>,
    {
        compose(self, next)
    }
}

/// A lens from `From` to `To` where `From` is guaranteed to contain the focus
/// of the lens (ie. get and put operations cannot fail).
///
/// These must also implement `PartialLens`, so a default implementation is
/// provided which will just unwrap the results of `try_get` and `try_put`.
pub trait Lens: PartialLens {
    /// Get the focus of the lens.
    fn get<R>(&self, s: R) -> Arc<Self::To>
    where
        R: AsRef<Self::From>,
    {
        self.try_get(s).unwrap()
    }

    /// Put a value into the lens, returning the updated `From` value.
    fn put<Convert, R>(&self, v: Convert, s: R) -> Self::From
    where
        R: AsRef<Self::From>,
        Arc<Self::To>: From<Convert>,
    {
        self.try_put(Some(v), s).unwrap()
    }

    /// Compose this lens with a lens from `To` to a new type `Next`, yielding
    /// a lens from `From` to `Next`.
    fn chain<L, Next>(&self, next: &L) -> Compose<Self::From, Self::To, Next, Self, L>
    where
        L: Lens<From = Self::To, To = Next>,
    {
        compose(self, next)
    }
}

pub struct Compose<A, B, C, L, R>
where
    L: PartialLens<From = A, To = B>,
    R: PartialLens<From = B, To = C>,
{
    left: Arc<L>,
    right: Arc<R>,
    phantom_a: PhantomData<A>,
    phantom_b: PhantomData<B>,
    phantom_c: PhantomData<C>,
}

impl<A, B, C, L, R> Clone for Compose<A, B, C, L, R>
where
    L: PartialLens<From = A, To = B>,
    R: PartialLens<From = B, To = C>,
{
    fn clone(&self) -> Self {
        Compose {
            left: self.left.clone(),
            right: self.right.clone(),
            phantom_a: PhantomData,
            phantom_b: PhantomData,
            phantom_c: PhantomData,
        }
    }
}

impl<A, B, C, L, R> PartialLens for Compose<A, B, C, L, R>
where
    L: PartialLens<From = A, To = B>,
    R: PartialLens<From = B, To = C>,
{
    type From = A;
    type To = C;

    fn try_get<Re>(&self, s: Re) -> Option<Arc<C>>
    where
        Re: AsRef<A>,
    {
        match self.left.try_get(s) {
            None => None,
            Some(s2) => self.right.try_get(s2),
        }
    }

    fn try_put<FromC, Re>(&self, v: Option<FromC>, s: Re) -> Option<A>
    where
        Re: AsRef<A>,
        Arc<C>: From<FromC>,
    {
        self.left
            .try_get(&s)
            .and_then(|s2| self.right.try_put(v, s2))
            .and_then(|s3| self.left.try_put(Some(s3), &s))
    }
}

impl<A, B, C, L, R> Lens for Compose<A, B, C, L, R>
where
    L: Lens<From = A, To = B>,
    R: Lens<From = B, To = C>,
{
}

/// Compose a lens from `A` to `B` with a lens from `B` to `C`, yielding
/// a lens from `A` to `C`.
pub fn compose<A, B, C, L, R>(left: &L, right: &R) -> Compose<A, B, C, L, R>
where
    L: PartialLens<From = A, To = B>,
    R: PartialLens<From = B, To = C>,
{
    Compose {
        left: Arc::new(left.clone()),
        right: Arc::new(right.clone()),
        phantom_a: PhantomData,
        phantom_b: PhantomData,
        phantom_c: PhantomData,
    }
}