convert_js/
option_like.rs1use wasm_bindgen::{JsCast, JsValue};
2
3use crate::{FromJs, ToJs, WrapJsCast};
4
5macro_rules! def_option_like {
6 (
7 $name:ident {
8 None = $name_none:ident = $js_none_doc:literal $js_none:expr,
9 condition = |$from_js_ident:ident| $js_is_none:expr,
10 Some = $name_some:ident $(,)?
11 }
12 ) => {
13 #[doc = concat!("Corresponding to `T | ", $js_none_doc, "`")]
14 #[doc = concat!("`", stringify!($name_none), "` => `", $js_none_doc, "`")]
18 #[doc = concat!("`", stringify!($name_some), "(value)` => `value`")]
20 #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
25 pub enum $name<T> {
26 $name_none,
27 $name_some(T),
28 }
29
30 impl<T> $name<T> {
31 #[inline]
32 pub fn from_option(v: Option<T>) -> Self {
33 if let Some(v) = v {
34 Self::$name_some(v)
35 } else {
36 Self::$name_none
37 }
38 }
39
40 #[inline]
41 pub fn into_option(self) -> Option<T> {
42 match self {
43 Self::$name_none => None,
44 Self::$name_some(v) => Some(v),
45 }
46 }
47
48 #[inline]
49 pub fn as_ref(&self) -> $name<&T> {
50 match self {
51 Self::$name_none => $name::$name_none,
52 Self::$name_some(v) => $name::$name_some(v),
53 }
54 }
55 }
56
57 impl<T: Clone> Clone for $name<T> {
58 #[inline]
59 fn clone(&self) -> Self {
60 match self {
61 Self::$name_some(x) => Self::$name_some(x.clone()),
62 Self::$name_none => Self::$name_none,
63 }
64 }
65
66 #[inline]
67 fn clone_from(&mut self, source: &Self) {
68 match (self, source) {
69 (Self::$name_some(to), Self::$name_some(from)) => to.clone_from(from),
70 (to, from) => *to = from.clone(),
71 }
72 }
73 }
74
75 impl<T> Default for $name<T> {
76 #[doc = concat!("Returns [`", stringify!($name_none), "`][", stringify!($name), "::", stringify!($name_none), "]")]
77 #[inline]
78 fn default() -> $name<T> {
79 Self::$name_none
80 }
81 }
82
83 impl<T> From<Option<T>> for $name<T> {
84 #[inline]
85 fn from(v: Option<T>) -> Self {
86 Self::from_option(v)
87 }
88 }
89
90 impl<T> Into<Option<T>> for $name<T> {
91 #[inline]
92 fn into(self) -> Option<T> {
93 self.into_option()
94 }
95 }
96
97 impl<T: ToJs> ToJs for $name<T> {
98 fn to_js(&self) -> wasm_bindgen::JsValue {
99 match self {
100 Self::$name_none => $js_none,
101 Self::$name_some(v) => v.to_js(),
102 }
103 }
104 }
105
106 impl<T: FromJs> FromJs for $name<T> {
107 type Error = T::Error;
108 fn from_js($from_js_ident: wasm_bindgen::JsValue) -> Result<Self, Self::Error> {
109 if $js_is_none {
110 Ok(Self::$name_none)
111 } else {
112 T::from_js($from_js_ident).map(Self::$name_some)
113 }
114 }
115 }
116
117 impl<T: JsCast> $name<WrapJsCast<T>> {
118 pub fn wrap_js_cast(v: T) -> Self {
119 Self::$name_some(WrapJsCast(v))
120 }
121 }
122 };
123}
124
125def_option_like! {
126 Nullable {
127 None = Null = "null" JsValue::NULL,
128 condition = |v| v.is_null(),
129 Some = NonNull,
130 }
131}
132
133def_option_like! {
134 Maybe {
135 None = Undefined = "undefined" JsValue::UNDEFINED,
136 condition = |v| v.is_undefined(),
137 Some = Defined,
138 }
139}