nvim_oxi_types/
conversion.rs1use 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 Deserialize(#[from] crate::serde::DeserializeError),
32
33 #[cfg(feature = "serde")]
34 #[error(transparent)]
35 Serialize(#[from] crate::serde::SerializeError),
36}
37
38pub trait FromObject: Sized {
40 fn from_object(object: Object) -> Result<Self, Error>;
41}
42
43pub trait ToObject {
45 fn to_object(self) -> Result<Object, Error>;
46}
47
48impl FromObject for Object {
49 fn from_object(obj: Object) -> Result<Self, Error> {
50 Ok(obj)
51 }
52}
53
54impl FromObject for () {
55 fn from_object(obj: Object) -> Result<Self, Error> {
56 match obj.kind() {
57 ObjectKind::Nil => Ok(()),
58
59 other => Err(Error::FromWrongType {
60 expected: "nil",
61 actual: other.as_static(),
62 }),
63 }
64 }
65}
66
67impl FromObject for Boolean {
68 fn from_object(obj: Object) -> Result<Self, Error> {
69 match obj.kind() {
70 ObjectKind::Boolean => Ok(unsafe { obj.as_boolean_unchecked() }),
71
72 other => Err(Error::FromWrongType {
73 expected: "bool",
74 actual: other.as_static(),
75 }),
76 }
77 }
78}
79
80impl FromObject for Integer {
81 fn from_object(obj: Object) -> Result<Self, Error> {
82 match obj.kind() {
83 ObjectKind::Integer
84 | ObjectKind::Buffer
85 | ObjectKind::Window
86 | ObjectKind::TabPage => Ok(unsafe { obj.as_integer_unchecked() }),
87
88 other => Err(Error::FromWrongType {
89 expected: "integer",
90 actual: other.as_static(),
91 }),
92 }
93 }
94}
95
96impl FromObject for Float {
97 fn from_object(obj: Object) -> Result<Self, Error> {
98 match obj.kind() {
99 ObjectKind::Float => Ok(unsafe { obj.as_float_unchecked() }),
100
101 other => Err(Error::FromWrongType {
102 expected: "float",
103 actual: other.as_static(),
104 }),
105 }
106 }
107}
108
109impl FromObject for crate::String {
110 fn from_object(obj: Object) -> Result<Self, Error> {
111 match obj.kind() {
112 ObjectKind::String => Ok(unsafe { obj.into_string_unchecked() }),
113
114 other => Err(Error::FromWrongType {
115 expected: "string",
116 actual: other.as_static(),
117 }),
118 }
119 }
120}
121
122impl FromObject for Array {
123 fn from_object(obj: Object) -> Result<Self, Error> {
124 match obj.kind() {
125 ObjectKind::Array => Ok(unsafe { obj.into_array_unchecked() }),
126
127 other => Err(Error::FromWrongType {
128 expected: "string",
129 actual: other.as_static(),
130 }),
131 }
132 }
133}
134
135impl FromObject for Dictionary {
136 fn from_object(obj: Object) -> Result<Self, Error> {
137 match obj.kind() {
138 ObjectKind::Dictionary => Ok(unsafe { obj.into_dict_unchecked() }),
139
140 other => Err(Error::FromWrongType {
141 expected: "string",
142 actual: other.as_static(),
143 }),
144 }
145 }
146}
147
148impl<A, R> FromObject for Function<A, R> {
149 fn from_object(obj: Object) -> Result<Self, Error> {
150 match obj.kind() {
151 ObjectKind::LuaRef => {
152 Ok(Self::from_ref(unsafe { obj.as_luaref_unchecked() }))
153 },
154
155 other => Err(Error::FromWrongType {
156 expected: "function",
157 actual: other.as_static(),
158 }),
159 }
160 }
161}
162
163macro_rules! from_int {
165 ($integer:ty) => {
166 impl FromObject for $integer {
167 fn from_object(obj: Object) -> Result<Self, Error> {
168 Integer::from_object(obj).map(Into::into)
169 }
170 }
171 };
172}
173
174from_int!(i128);
175
176macro_rules! try_from_int {
178 ($integer:ty) => {
179 impl FromObject for $integer {
180 fn from_object(obj: Object) -> Result<Self, Error> {
181 Integer::from_object(obj).and_then(|n| Ok(n.try_into()?))
182 }
183 }
184 };
185}
186
187try_from_int!(i8);
188try_from_int!(u8);
189try_from_int!(i16);
190try_from_int!(u16);
191try_from_int!(i32);
192try_from_int!(u32);
193try_from_int!(u64);
194try_from_int!(u128);
195try_from_int!(isize);
196try_from_int!(usize);
197
198impl FromObject for f32 {
199 fn from_object(obj: Object) -> Result<Self, Error> {
200 Ok(Float::from_object(obj)? as _)
201 }
202}
203
204impl FromObject for String {
205 fn from_object(obj: Object) -> Result<Self, Error> {
206 crate::String::from_object(obj)
207 .map(|nvim_str| nvim_str.to_string_lossy().into())
208 }
209}
210
211impl<T> FromObject for Option<T>
212where
213 T: FromObject,
214{
215 fn from_object(obj: Object) -> Result<Self, Error> {
216 (!obj.is_nil()).then(|| T::from_object(obj)).transpose()
217 }
218}
219
220impl<T> FromObject for Vec<T>
221where
222 T: FromObject,
223{
224 fn from_object(obj: Object) -> Result<Self, Error> {
225 Array::from_object(obj)?
226 .into_iter()
227 .map(FromObject::from_object)
228 .collect()
229 }
230}
231
232impl<T> ToObject for T
233where
234 T: Into<Object>,
235{
236 fn to_object(self) -> Result<Object, Error> {
237 Ok(self.into())
238 }
239}
240
241macro_rules! bigint_to_obj {
243 ($type:ty) => {
244 impl ToObject for $type {
245 fn to_object(self) -> Result<Object, Error> {
246 Ok(i64::try_from(self)?.into())
247 }
248 }
249 };
250}
251
252bigint_to_obj!(u64);
253bigint_to_obj!(isize);
254bigint_to_obj!(usize);
255bigint_to_obj!(i128);
256bigint_to_obj!(u128);
257
258impl<T> ToObject for Vec<T>
259where
260 T: ToObject,
261{
262 fn to_object(self) -> Result<Object, Error> {
263 Ok(self
264 .into_iter()
265 .map(ToObject::to_object)
266 .collect::<Result<Array, Error>>()?
267 .into())
268 }
269}
270
271impl<K, V> ToObject for HashMap<K, V>
272where
273 K: Into<crate::String>,
274 V: ToObject,
275{
276 fn to_object(self) -> Result<Object, Error> {
277 self.into_iter()
278 .map(|(k, v)| Ok((k, v.to_object()?)))
279 .collect::<Result<Dictionary, Error>>()
280 .map(Into::into)
281 }
282}