1#[macro_export]
15macro_rules! dict {
16 () => {{
17 ::nvim_oxi::Dictionary::default()
18 }};
19 ( $( $key:tt : $value:expr ),+ $(,)? ) => {{
20 let mut map: ::std::collections::BTreeMap<
21 ::std::borrow::Cow<'static, str>,
22 ::nvim_oxi::Object
23 > = ::std::collections::BTreeMap::new();
24 $(
25 let k: ::std::borrow::Cow<'static, str> = $crate::__dict_key_to_cow!($key);
26 let v: ::nvim_oxi::Object = ::nvim_oxi::Object::from($value);
27 map.insert(k, v);
28 )+
29 ::nvim_oxi::Dictionary::from_iter(map)
30 }};
31}
32
33#[doc(hidden)]
34#[macro_export]
35macro_rules! __dict_key_to_cow {
36 ($k:literal) => {
37 ::std::borrow::Cow::Borrowed($k)
38 };
39 ($k:ident) => {
40 ::std::borrow::Cow::Borrowed(::std::stringify!($k))
41 };
42 ($k:expr) => {
43 ::std::borrow::Cow::Owned(::std::convert::Into::<::std::string::String>::into($k))
44 };
45}
46
47#[macro_export]
52macro_rules! impl_nvim_deserializable {
53 ($ty:ty) => {
54 impl ::nvim_oxi::conversion::FromObject for $ty {
55 fn from_object(obj: ::nvim_oxi::Object) -> ::std::result::Result<Self, ::nvim_oxi::conversion::Error> {
56 <Self as ::serde::Deserialize>::deserialize(::nvim_oxi::serde::Deserializer::new(obj))
57 .map_err(::std::convert::Into::into)
58 }
59 }
60
61 impl ::nvim_oxi::lua::Poppable for $ty {
62 unsafe fn pop(
63 lstate: *mut ::nvim_oxi::lua::ffi::State,
64 ) -> ::std::result::Result<Self, ::nvim_oxi::lua::Error> {
65 unsafe {
69 let obj = ::nvim_oxi::Object::pop(lstate)?;
70 <Self as ::nvim_oxi::conversion::FromObject>::from_object(obj)
71 .map_err(::nvim_oxi::lua::Error::pop_error_from_err::<Self, _>)
72 }
73 }
74 }
75 };
76}
77
78#[macro_export]
80macro_rules! fn_from {
81 ($path:path) => {
83 ::nvim_oxi::Object::from(::nvim_oxi::Function::from_fn($path))
84 };
85 ($($tokens:tt)+) => {
87 ::nvim_oxi::Object::from(::nvim_oxi::Function::from_fn($($tokens)+))
88 };
89}
90
91#[cfg(test)]
92mod tests {
93 use nvim_oxi::Dictionary;
94 use nvim_oxi::Object;
95
96 use crate::dict::DictionaryExt as _;
97
98 #[test]
99 fn dict_macro_empty_creates_empty_dictionary() {
100 let actual = dict!();
101 assert_eq!(actual.len(), 0);
102 }
103
104 #[test]
105 fn dict_macro_creates_a_dictionary_with_basic_key_value_pairs() {
106 let actual = dict! { "foo": 1, bar: "baz", "num": 3_i64 };
107 let expected = Dictionary::from_iter([
108 ("bar", Object::from("baz")),
109 ("foo", Object::from(1)),
110 ("num", Object::from(3_i64)),
111 ]);
112 assert_eq!(actual, expected);
113 }
114
115 #[test]
116 fn dict_macro_creates_nested_dictionaries() {
117 let k = String::from("alpha");
118 let inner = dict! { inner_key: "value" };
119 let actual = dict! { (k): 10_i64, "beta": inner.clone() };
120 let expected = Dictionary::from_iter([("alpha", Object::from(10_i64)), ("beta", Object::from(inner))]);
121 assert_eq!(actual, expected);
122 }
123
124 #[test]
125 fn dictionary_ext_get_t_works_as_expected() {
126 let dict = dict! { "foo": "42" };
127 assert2::assert!(let Err(err) = dict.get_t::<nvim_oxi::String>("bar"));
128 assert_eq!(err.format_current_context().to_string(), "missing dict value");
129 assert_eq!(dict.get_t::<nvim_oxi::String>("foo").unwrap(), "42");
130
131 let dict = dict! { "foo": 42 };
132 assert2::assert!(let Err(err) = dict.get_t::<nvim_oxi::String>("foo"));
133 assert_eq!(err.format_current_context().to_string(), "unexpected object kind");
134 }
135
136 #[test]
137 fn dictionary_ext_get_dict_works_as_expected() {
138 let dict = dict! { "foo": "42" };
139 assert_eq!(dict.get_dict(&["bar"]).unwrap(), None);
140
141 let dict = dict! { "foo": 42 };
142 assert2::assert!(let Err(err) = dict.get_dict(&["foo"]));
143 assert_eq!(err.format_current_context().to_string(), "unexpected object kind");
144
145 let expected = dict! { "bar": "42" };
146 let dict = dict! { "foo": expected.clone() };
147 assert_eq!(dict.get_dict(&["foo"]).unwrap(), Some(expected));
148 }
149}