neon/types_impl/extract/
either.rs

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
use std::{any, error, fmt};

use either::Either;

use crate::{
    context::Cx,
    handle::Handle,
    object::Object,
    result::{JsResult, NeonResult},
    types::{
        extract::{private, TryFromJs, TryIntoJs},
        JsError, JsValue,
    },
};

impl<'cx, L, R> TryFromJs<'cx> for Either<L, R>
where
    L: TryFromJs<'cx>,
    R: TryFromJs<'cx>,
{
    type Error = Error<L::Error, R::Error>;

    fn try_from_js(
        cx: &mut Cx<'cx>,
        v: Handle<'cx, JsValue>,
    ) -> NeonResult<Result<Self, Self::Error>> {
        let left = match L::try_from_js(cx, v)? {
            Ok(l) => return Ok(Ok(Either::Left(l))),
            Err(l) => l,
        };

        let right = match R::try_from_js(cx, v)? {
            Ok(r) => return Ok(Ok(Either::Right(r))),
            Err(r) => r,
        };

        Ok(Err(Error::new::<L, R>(left, right)))
    }
}

impl<'cx, L, R> TryIntoJs<'cx> for Either<L, R>
where
    L: TryIntoJs<'cx>,
    R: TryIntoJs<'cx>,
{
    type Value = JsValue;

    fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
        match self {
            Either::Left(v) => v.try_into_js(cx).map(|v| v.upcast()),
            Either::Right(v) => v.try_into_js(cx).map(|v| v.upcast()),
        }
    }
}

impl<L, R> private::Sealed for Either<L, R> {}

#[derive(Debug)]
pub struct Error<L, R> {
    left: (&'static str, L),
    right: (&'static str, R),
}

impl<'cx, L, R> Error<L, R> {
    fn new<LT, RT>(left: L, right: R) -> Self
    where
        LT: TryFromJs<'cx, Error = L>,
        RT: TryFromJs<'cx, Error = R>,
    {
        Self {
            left: (any::type_name::<LT>(), left),
            right: (any::type_name::<RT>(), right),
        }
    }
}

impl<L, R> fmt::Display for Error<L, R>
where
    L: fmt::Display,
    R: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Either::Left: {}", self.left.1)?;
        write!(f, "Either::Right: {}", self.right.1)
    }
}

impl<L, R> error::Error for Error<L, R>
where
    L: error::Error,
    R: error::Error,
{
}

impl<'cx, L, R> TryIntoJs<'cx> for Error<L, R>
where
    L: TryIntoJs<'cx>,
    R: TryIntoJs<'cx>,
{
    type Value = JsError;

    fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
        let err = JsError::type_error(
            cx,
            format!("expected either {} or {}", self.left.0, self.right.0,),
        )?;

        err.prop(cx, "left").set(self.left.1)?;
        err.prop(cx, "right").set(self.right.1)?;

        Ok(err)
    }
}

impl<L, R> private::Sealed for Error<L, R> {}