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
use either::Either;

use crate::requests::Payload;

/// Represents types having payload inside.
///
/// This trait is something between [`DerefMut`] and [`BorrowMut`] — it allows
/// only one implementation per type (the [output type] is associated, not
/// generic), has implementations for all types `P` such `P: `[`Payload`], but
/// has no magic compiler support like [`DerefMut`] does nor does it require
/// any laws about `Eq`, `Ord` and `Hash` as [`BorrowMut`] does.
///
/// Also the [output type] is bounded by the [`Payload`] trait.
///
/// This trait is mostly used to implement payload setters (on both payloads &
/// requests), so you probably won't find yourself using it directly.
///
/// [`DerefMut`]: std::ops::DerefMut
/// [`BorrowMut`]: std::borrow::BorrowMut
/// [`Payload`]: crate::requests::Payload
/// [output type]: HasPayload::Payload
pub trait HasPayload {
    /// The type of the payload contained.
    type Payload: Payload;

    /// Gain mutable access to the underlying payload.
    fn payload_mut(&mut self) -> &mut Self::Payload;

    /// Gain immutable access to the underlying payload.
    fn payload_ref(&self) -> &Self::Payload;

    /// Update payload with a function
    fn with_payload_mut<F>(mut self, f: F) -> Self
    where
        Self: Sized,
        F: FnOnce(&mut Self::Payload),
    {
        f(self.payload_mut());
        self
    }
}

impl<P> HasPayload for P
where
    P: Payload,
{
    type Payload = Self;

    fn payload_mut(&mut self) -> &mut Self::Payload {
        self
    }

    fn payload_ref(&self) -> &Self::Payload {
        self
    }
}

impl<L, R> HasPayload for Either<L, R>
where
    L: HasPayload,
    R: HasPayload<Payload = L::Payload>,
{
    type Payload = L::Payload;

    fn payload_mut(&mut self) -> &mut Self::Payload {
        self.as_mut().either(<_>::payload_mut, <_>::payload_mut)
    }

    fn payload_ref(&self) -> &Self::Payload {
        self.as_ref().either(<_>::payload_ref, <_>::payload_ref)
    }
}