1use std::collections::HashMap;
4
5use thiserror::Error as ThisError;
6
7use crate::array::ArrayFromTupleError;
8use crate::{
9 Array,
10 Boolean,
11 Dictionary,
12 Float,
13 Function,
14 Integer,
15 Object,
16 ObjectKind,
17};
18
19#[derive(Clone, Debug, Eq, PartialEq, ThisError)]
20pub enum Error {
21 #[error("Was expecting a \"{expected}\" but received a \"{actual}\"")]
22 FromWrongType { expected: &'static str, actual: &'static str },
23
24 #[error(transparent)]
25 FromInt(#[from] std::num::TryFromIntError),
26
27 #[error(transparent)]
28 FromUtf8(#[from] std::string::FromUtf8Error),
29
30 #[cfg(feature = "serde")]
31 #[error(transparent)]
32 Deserialize(#[from] crate::serde::DeserializeError),
33
34 #[cfg(feature = "serde")]
35 #[error(transparent)]
36 Serialize(#[from] crate::serde::SerializeError),
37
38 #[doc(hidden)]
39 #[error("{0}")]
40 Other(String),
41}
42
43pub trait FromObject: Sized {
45 fn from_object(object: Object) -> Result<Self, Error>;
46}
47
48pub trait ToObject {
50 fn to_object(self) -> Result<Object, Error>;
51}
52
53impl FromObject for Object {
54 fn from_object(obj: Object) -> Result<Self, Error> {
55 Ok(obj)
56 }
57}
58
59impl FromObject for () {
60 fn from_object(obj: Object) -> Result<Self, Error> {
61 match obj.kind() {
62 ObjectKind::Nil => Ok(()),
63
64 other => Err(Error::FromWrongType {
65 expected: "nil",
66 actual: other.as_static(),
67 }),
68 }
69 }
70}
71
72impl FromObject for Boolean {
73 fn from_object(obj: Object) -> Result<Self, Error> {
74 match obj.kind() {
75 ObjectKind::Boolean => Ok(unsafe { obj.as_boolean_unchecked() }),
76
77 other => Err(Error::FromWrongType {
78 expected: "bool",
79 actual: other.as_static(),
80 }),
81 }
82 }
83}
84
85impl TryFrom<Object> for Integer {
86 type Error = Error;
87
88 fn try_from(obj: Object) -> Result<Self, Self::Error> {
89 match obj.kind() {
90 ObjectKind::Integer
91 | ObjectKind::Buffer
92 | ObjectKind::Window
93 | ObjectKind::TabPage => Ok(unsafe { obj.as_integer_unchecked() }),
94
95 other => Err(Error::FromWrongType {
96 expected: "integer",
97 actual: other.as_static(),
98 }),
99 }
100 }
101}
102
103impl FromObject for Float {
104 fn from_object(obj: Object) -> Result<Self, Error> {
105 match obj.kind() {
106 ObjectKind::Float => Ok(unsafe { obj.as_float_unchecked() }),
107
108 other => Err(Error::FromWrongType {
109 expected: "float",
110 actual: other.as_static(),
111 }),
112 }
113 }
114}
115
116impl FromObject for Array {
117 fn from_object(obj: Object) -> Result<Self, Error> {
118 match obj.kind() {
119 ObjectKind::Array => Ok(unsafe { obj.into_array_unchecked() }),
120
121 other => Err(Error::FromWrongType {
122 expected: "string",
123 actual: other.as_static(),
124 }),
125 }
126 }
127}
128
129impl<A, R> FromObject for Function<A, R> {
130 fn from_object(obj: Object) -> Result<Self, Error> {
131 match obj.kind() {
132 ObjectKind::LuaRef => {
133 Ok(Self::from_ref(unsafe { obj.as_luaref_unchecked() }))
134 },
135
136 other => Err(Error::FromWrongType {
137 expected: "function",
138 actual: other.as_static(),
139 }),
140 }
141 }
142}
143
144impl<T: TryFrom<Object, Error = Error>> FromObject for T {
145 #[inline]
146 fn from_object(obj: Object) -> Result<Self, Error> {
147 T::try_from(obj)
148 }
149}
150
151macro_rules! from_int {
153 ($integer:ty) => {
154 impl FromObject for $integer {
155 fn from_object(obj: Object) -> Result<Self, Error> {
156 Integer::from_object(obj).map(Into::into)
157 }
158 }
159 };
160}
161
162from_int!(i128);
163
164macro_rules! int_try_from_obj {
166 ($integer:ty) => {
167 impl TryFrom<Object> for $integer {
168 type Error = Error;
169
170 fn try_from(obj: Object) -> Result<Self, Self::Error> {
171 Integer::try_from(obj)
172 .and_then(|n| n.try_into().map_err(Into::into))
173 }
174 }
175 };
176}
177
178int_try_from_obj!(i8);
179int_try_from_obj!(u8);
180int_try_from_obj!(i16);
181int_try_from_obj!(u16);
182int_try_from_obj!(i32);
183int_try_from_obj!(u32);
184int_try_from_obj!(u64);
185int_try_from_obj!(u128);
186int_try_from_obj!(isize);
187int_try_from_obj!(usize);
188
189impl FromObject for f32 {
190 fn from_object(obj: Object) -> Result<Self, Error> {
191 Ok(Float::from_object(obj)? as _)
192 }
193}
194
195impl FromObject for String {
196 fn from_object(obj: Object) -> Result<Self, Error> {
197 crate::String::from_object(obj)
198 .map(|nvim_str| nvim_str.to_string_lossy().into())
199 }
200}
201
202impl<T> FromObject for Option<T>
203where
204 T: FromObject,
205{
206 fn from_object(obj: Object) -> Result<Self, Error> {
207 (!obj.is_nil()).then(|| T::from_object(obj)).transpose()
208 }
209}
210
211impl<T> FromObject for Vec<T>
212where
213 T: FromObject,
214{
215 fn from_object(obj: Object) -> Result<Self, Error> {
216 Array::from_object(obj)?
217 .into_iter()
218 .map(FromObject::from_object)
219 .collect()
220 }
221}
222
223macro_rules! tuple_from_object {
226 ($($ty:ident)*) => {
227 impl<Err, $($ty,)*> FromObject for ($($ty,)*)
228 where
229 $($ty: TryFrom<Object, Error = Err>,)*
230 Err: Into<self::Error> + core::error::Error,
231 {
232 #[inline]
233 #[allow(non_snake_case)]
234 fn from_object(obj: Object) -> Result<Self, Error> {
235 Array::from_object(obj)?
236 .try_into()
237 .map_err(|err: ArrayFromTupleError<Err>| match err {
238 ArrayFromTupleError::ElementFromObject { error, .. } => error.into(),
239 err @ ArrayFromTupleError::NotEnoughElements { .. } => Error::Other(err.to_string()),
240 })
241 }
242 }
243 };
244}
245
246tuple_from_object!(A);
247tuple_from_object!(A B);
248tuple_from_object!(A B C);
249tuple_from_object!(A B C D);
250tuple_from_object!(A B C D E);
251tuple_from_object!(A B C D E F);
252tuple_from_object!(A B C D E F G);
253tuple_from_object!(A B C D E F G H);
254tuple_from_object!(A B C D E F G H I);
255tuple_from_object!(A B C D E F G H I J);
256tuple_from_object!(A B C D E F G H I J K);
257tuple_from_object!(A B C D E F G H I J K L);
258tuple_from_object!(A B C D E F G H I J K L M);
259tuple_from_object!(A B C D E F G H I J K L M N);
260tuple_from_object!(A B C D E F G H I J K L M N O);
261tuple_from_object!(A B C D E F G H I J K L M N O P);
262
263impl<T> ToObject for T
264where
265 T: Into<Object>,
266{
267 fn to_object(self) -> Result<Object, Error> {
268 Ok(self.into())
269 }
270}
271
272macro_rules! bigint_to_obj {
274 ($type:ty) => {
275 impl ToObject for $type {
276 fn to_object(self) -> Result<Object, Error> {
277 Ok(i64::try_from(self)?.into())
278 }
279 }
280 };
281}
282
283bigint_to_obj!(u64);
284bigint_to_obj!(isize);
285bigint_to_obj!(usize);
286bigint_to_obj!(i128);
287bigint_to_obj!(u128);
288
289impl<T> ToObject for Vec<T>
290where
291 T: ToObject,
292{
293 fn to_object(self) -> Result<Object, Error> {
294 Ok(self
295 .into_iter()
296 .map(ToObject::to_object)
297 .collect::<Result<Array, Error>>()?
298 .into())
299 }
300}
301
302impl<K, V> ToObject for HashMap<K, V>
303where
304 K: Into<crate::String>,
305 V: ToObject,
306{
307 fn to_object(self) -> Result<Object, Error> {
308 self.into_iter()
309 .map(|(k, v)| Ok((k, v.to_object()?)))
310 .collect::<Result<Dictionary, Error>>()
311 .map(Into::into)
312 }
313}