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
use crate::protocol::{Protocol, ProtocolDescription};

pub trait WalkerError<'value, 'ctx: 'value> {
    fn wrong_visit<P: Protocol<'value, 'ctx>>() -> Self;
    fn needs_hint() -> Self;
}

pub trait VisitorError<'value, 'ctx: 'value> {
    fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self;
}

#[derive(thiserror::Error, Debug)]
pub enum UniError<WalkerErr, VisitorErr> {
    #[error(transparent)]
    Walker(WalkerErr),

    #[error(transparent)]
    Visitor(VisitorErr),
}

#[derive(thiserror::Error, Debug)]
#[error("{message}")]
pub struct BasicError {
    message: &'static str,
}

impl BasicError {
    pub fn new(message: &'static str) -> Self {
        Self { message }
    }

    pub fn message(&self) -> &'static str {
        self.message
    }
}

impl<'value, 'ctx: 'value> WalkerError<'value, 'ctx> for BasicError {
    fn wrong_visit<P: Protocol<'value, 'ctx>>() -> Self {
        Self::new("wrong protocol for visit")
    }

    fn needs_hint() -> Self {
        Self::new("walker needs hint from visitor")
    }
}

impl<'value, 'ctx: 'value> VisitorError<'value, 'ctx> for BasicError {
    fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
        Self::new("wrong protocol for hint")
    }
}

/// Error wrapper that adds a missing variant.
#[derive(thiserror::Error, Debug)]
pub enum Missing<E> {
    /// The value was never visted.
    #[error("value is missing after walking")]
    Missing,

    /// Another error.
    #[error(transparent)]
    Error(#[from] E),
}

impl<'value, 'ctx: 'value, E: VisitorError<'value, 'ctx>> VisitorError<'value, 'ctx>
    for Missing<E>
{
    fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
        E::wrong_hint::<P>().into()
    }
}

#[derive(thiserror::Error, Debug)]
pub enum WrongProtocol<E> {
    /// The wrong protocol was given in a query.
    #[error("wrong protocol, expected: `{expected}`, got: `{got}`")]
    WrongProtocol {
        expected: ProtocolDescription,
        got: ProtocolDescription,
    },

    /// Another error.
    #[error(transparent)]
    Error(#[from] E),
}

impl<'value, 'ctx: 'value, E: VisitorError<'value, 'ctx>> VisitorError<'value, 'ctx>
    for WrongProtocol<E>
{
    fn wrong_hint<P: Protocol<'value, 'ctx>>() -> Self {
        E::wrong_hint::<P>().into()
    }
}