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::new();
21 $(
22 let k: ::std::borrow::Cow<'static, str> = $crate::__dict_key_to_cow!($key);
23 let v: ::nvim_oxi::Object = ::nvim_oxi::Object::from($value);
24 map.insert(k, v);
25 )+
26 ::nvim_oxi::Dictionary::from_iter(map)
27 }};
28}
29
30#[doc(hidden)]
31#[macro_export]
32macro_rules! __dict_key_to_cow {
33 ($k:literal) => {
34 ::std::borrow::Cow::Borrowed($k)
35 };
36 ($k:ident) => {
37 ::std::borrow::Cow::Borrowed(::std::stringify!($k))
38 };
39 ($k:expr) => {
40 ::std::borrow::Cow::Owned(::std::convert::Into::<::std::string::String>::into($k))
41 };
42}
43
44#[macro_export]
49macro_rules! impl_nvim_deserializable {
50 ($ty:ty) => {
51 impl ::nvim_oxi::conversion::FromObject for $ty {
52 fn from_object(obj: ::nvim_oxi::Object) -> ::std::result::Result<Self, ::nvim_oxi::conversion::Error> {
53 <Self as ::serde::Deserialize>::deserialize(::nvim_oxi::serde::Deserializer::new(obj))
54 .map_err(::std::convert::Into::into)
55 }
56 }
57
58 impl ::nvim_oxi::lua::Poppable for $ty {
59 unsafe fn pop(
60 lstate: *mut ::nvim_oxi::lua::ffi::State,
61 ) -> ::std::result::Result<Self, ::nvim_oxi::lua::Error> {
62 unsafe {
66 let obj = ::nvim_oxi::Object::pop(lstate)?;
67 <Self as ::nvim_oxi::conversion::FromObject>::from_object(obj)
68 .map_err(::nvim_oxi::lua::Error::pop_error_from_err::<Self, _>)
69 }
70 }
71 }
72 };
73}
74
75#[macro_export]
77macro_rules! fn_from {
78 ($path:path) => {
80 ::nvim_oxi::Object::from(::nvim_oxi::Function::from_fn($path))
81 };
82 ($($tokens:tt)+) => {
84 ::nvim_oxi::Object::from(::nvim_oxi::Function::from_fn($($tokens)+))
85 };
86}
87
88#[cfg(test)]
89mod tests {
90 use nvim_oxi::Dictionary;
91 use nvim_oxi::Object;
92 use test_that::prelude::*;
93
94 use crate::dict::DictionaryExt;
95
96 #[test]
97 fn test_dict_macro_empty_creates_empty_dictionary() {
98 let actual = dict!();
99 assert_eq!(actual.len(), 0);
100 }
101
102 #[test]
103 fn test_dict_macro_creates_a_dictionary_with_basic_key_value_pairs() {
104 let actual = dict! { "foo": 1, bar: "baz", "num": 3_i64 };
105 let expected = Dictionary::from_iter([
106 ("bar", Object::from("baz")),
107 ("foo", Object::from(1)),
108 ("num", Object::from(3_i64)),
109 ]);
110 assert_eq!(actual, expected);
111 }
112
113 #[test]
114 fn test_dict_macro_creates_nested_dictionaries() {
115 let k = String::from("alpha");
116 let inner = dict! { inner_key: "value" };
117 let actual = dict! { (k): 10_i64, "beta": inner.clone() };
118 let expected = Dictionary::from_iter([("alpha", Object::from(10_i64)), ("beta", Object::from(inner))]);
119 assert_eq!(actual, expected);
120 }
121
122 #[test]
123 fn test_dictionary_ext_get_t_when_key_exists_returns_typed_value() {
124 let dict = dict! { "foo": "42" };
125 assert_that!(
126 (dict.get_t::<nvim_oxi::String>("bar")).map(|_| ()),
127 err(result_of!(
128 |err: &rootcause::Report| err.format_current_context().to_string(),
129 eq("missing dict value")
130 ))
131 );
132 assert_eq!(dict.get_t::<nvim_oxi::String>("foo").unwrap(), "42");
133
134 let dict = dict! { "foo": 42 };
135 assert_that!(
136 (dict.get_t::<nvim_oxi::String>("foo")).map(|_| ()),
137 err(result_of!(
138 |err: &rootcause::Report| err.format_current_context().to_string(),
139 eq("unexpected object kind")
140 ))
141 );
142 }
143
144 #[test]
145 fn test_dictionary_ext_get_dict_when_key_exists_returns_dictionary() {
146 let dict = dict! { "foo": "42" };
147 assert_eq!(dict.get_dict(&["bar"]).unwrap(), None);
148
149 let dict = dict! { "foo": 42 };
150 assert_that!(
151 (dict.get_dict(&["foo"])).map(|_| ()),
152 err(result_of!(
153 |err: &rootcause::Report| err.format_current_context().to_string(),
154 eq("unexpected object kind")
155 ))
156 );
157
158 let expected = dict! { "bar": "42" };
159 let dict = dict! { "foo": expected.clone() };
160 assert_eq!(dict.get_dict(&["foo"]).unwrap(), Some(expected));
161 }
162}