1use std::collections::HashMap;
4
5use thiserror::Error as ThisError;
6
7use crate::{
8 Array,
9 Boolean,
10 Dictionary,
11 Float,
12 Function,
13 Integer,
14 Object,
15 ObjectKind,
16};
17
18#[derive(Clone, Debug, Eq, PartialEq, ThisError)]
19pub enum Error {
20 #[error("Was expecting a \"{expected}\" but received a \"{actual}\"")]
21 FromWrongType { expected: &'static str, actual: &'static str },
22
23 #[error(transparent)]
24 FromInt(#[from] std::num::TryFromIntError),
25
26 #[error(transparent)]
27 FromUtf8(#[from] std::string::FromUtf8Error),
28
29 #[cfg(feature = "serde")]
30 #[error(transparent)]
31 Serde(#[from] crate::serde::Error),
32}
33
34pub trait FromObject: Sized {
36 fn from_object(object: Object) -> Result<Self, Error>;
37}
38
39pub trait ToObject {
41 fn to_object(self) -> Result<Object, Error>;
42}
43
44impl FromObject for () {
45 fn from_object(obj: Object) -> Result<Self, Error> {
46 match obj.kind() {
47 ObjectKind::Nil => Ok(()),
48
49 other => Err(Error::FromWrongType {
50 expected: "nil",
51 actual: other.as_static(),
52 }),
53 }
54 }
55}
56
57impl FromObject for Boolean {
58 fn from_object(obj: Object) -> Result<Self, Error> {
59 match obj.kind() {
60 ObjectKind::Boolean => Ok(unsafe { obj.as_boolean_unchecked() }),
61
62 other => Err(Error::FromWrongType {
63 expected: "bool",
64 actual: other.as_static(),
65 }),
66 }
67 }
68}
69
70impl FromObject for Integer {
71 fn from_object(obj: Object) -> Result<Self, Error> {
72 match obj.kind() {
73 ObjectKind::Integer => Ok(unsafe { obj.as_integer_unchecked() }),
74
75 other => Err(Error::FromWrongType {
76 expected: "integer",
77 actual: other.as_static(),
78 }),
79 }
80 }
81}
82
83impl FromObject for Float {
84 fn from_object(obj: Object) -> Result<Self, Error> {
85 match obj.kind() {
86 ObjectKind::Float => Ok(unsafe { obj.as_float_unchecked() }),
87
88 other => Err(Error::FromWrongType {
89 expected: "float",
90 actual: other.as_static(),
91 }),
92 }
93 }
94}
95
96impl FromObject for crate::String {
97 fn from_object(obj: Object) -> Result<Self, Error> {
98 match obj.kind() {
99 ObjectKind::String => Ok(unsafe { obj.into_string_unchecked() }),
100
101 other => Err(Error::FromWrongType {
102 expected: "string",
103 actual: other.as_static(),
104 }),
105 }
106 }
107}
108
109impl FromObject for Array {
110 fn from_object(obj: Object) -> Result<Self, Error> {
111 match obj.kind() {
112 ObjectKind::Array => Ok(unsafe { obj.into_array_unchecked() }),
113
114 other => Err(Error::FromWrongType {
115 expected: "string",
116 actual: other.as_static(),
117 }),
118 }
119 }
120}
121
122impl FromObject for Dictionary {
123 fn from_object(obj: Object) -> Result<Self, Error> {
124 match obj.kind() {
125 ObjectKind::Dictionary => Ok(unsafe { obj.into_dict_unchecked() }),
126
127 other => Err(Error::FromWrongType {
128 expected: "string",
129 actual: other.as_static(),
130 }),
131 }
132 }
133}
134
135impl<A, R> FromObject for Function<A, R> {
136 fn from_object(obj: Object) -> Result<Self, Error> {
137 match obj.kind() {
138 ObjectKind::LuaRef => {
139 Ok(Self::from_ref(unsafe { obj.as_luaref_unchecked() }))
140 },
141
142 other => Err(Error::FromWrongType {
143 expected: "function",
144 actual: other.as_static(),
145 }),
146 }
147 }
148}
149
150macro_rules! from_int {
152 ($integer:ty) => {
153 impl FromObject for $integer {
154 fn from_object(obj: Object) -> Result<Self, Error> {
155 Integer::from_object(obj).map(Into::into)
156 }
157 }
158 };
159}
160
161from_int!(i128);
162
163macro_rules! try_from_int {
165 ($integer:ty) => {
166 impl FromObject for $integer {
167 fn from_object(obj: Object) -> Result<Self, Error> {
168 Integer::from_object(obj).and_then(|n| Ok(n.try_into()?))
169 }
170 }
171 };
172}
173
174try_from_int!(i8);
175try_from_int!(u8);
176try_from_int!(i16);
177try_from_int!(u16);
178try_from_int!(i32);
179try_from_int!(u32);
180try_from_int!(u64);
181try_from_int!(u128);
182try_from_int!(isize);
183try_from_int!(usize);
184
185impl FromObject for f32 {
186 fn from_object(obj: Object) -> Result<Self, Error> {
187 Ok(Float::from_object(obj)? as _)
188 }
189}
190
191impl FromObject for String {
192 fn from_object(obj: Object) -> Result<Self, Error> {
193 crate::String::from_object(obj)
194 .and_then(|nvim_str| Ok(nvim_str.into_string()?))
195 }
196}
197
198impl<T> FromObject for Option<T>
199where
200 T: FromObject,
201{
202 fn from_object(obj: Object) -> Result<Self, Error> {
203 (!obj.is_nil()).then(|| T::from_object(obj)).transpose()
204 }
205}
206
207impl<T> FromObject for Vec<T>
208where
209 T: FromObject,
210{
211 fn from_object(obj: Object) -> Result<Self, Error> {
212 Array::from_object(obj)?
213 .into_iter()
214 .map(FromObject::from_object)
215 .collect()
216 }
217}
218
219impl<T> ToObject for T
220where
221 T: Into<Object>,
222{
223 fn to_object(self) -> Result<Object, Error> {
224 Ok(self.into())
225 }
226}
227
228macro_rules! bigint_to_obj {
230 ($type:ty) => {
231 impl ToObject for $type {
232 fn to_object(self) -> Result<Object, Error> {
233 Ok(i64::try_from(self)?.into())
234 }
235 }
236 };
237}
238
239bigint_to_obj!(u64);
240bigint_to_obj!(isize);
241bigint_to_obj!(usize);
242bigint_to_obj!(i128);
243bigint_to_obj!(u128);
244
245impl<T> ToObject for Vec<T>
246where
247 T: ToObject,
248{
249 fn to_object(self) -> Result<Object, Error> {
250 Ok(self
251 .into_iter()
252 .map(ToObject::to_object)
253 .collect::<Result<Array, Error>>()?
254 .into())
255 }
256}
257
258impl<K, V> ToObject for HashMap<K, V>
259where
260 K: Into<crate::String>,
261 V: ToObject,
262{
263 fn to_object(self) -> Result<Object, Error> {
264 self.into_iter()
265 .map(|(k, v)| Ok((k, v.to_object()?)))
266 .collect::<Result<Dictionary, Error>>()
267 .map(Into::into)
268 }
269}