1use std::ffi::{CStr, CString};
17
18use crate::memgraph::*;
19use crate::mgp::*;
20use crate::result::*;
21use crate::value::*;
22#[double]
24use crate::mgp::ffi;
25use mockall_double::double;
26
27pub struct Map {
28 ptr: *mut mgp_map,
29 memgraph: Memgraph,
30}
31
32impl Drop for Map {
33 fn drop(&mut self) {
34 unsafe {
35 if !self.ptr.is_null() {
36 ffi::mgp_map_destroy(self.ptr);
37 }
38 }
39 }
40}
41
42pub struct MapItem {
44 pub key: CString,
45 pub value: Value,
46}
47
48pub struct MapIterator {
49 ptr: *mut mgp_map_items_iterator,
50 is_first: bool,
51 memgraph: Memgraph,
52}
53
54impl MapIterator {
55 pub(crate) fn new(ptr: *mut mgp_map_items_iterator, memgraph: &Memgraph) -> MapIterator {
56 MapIterator {
57 ptr,
58 is_first: true,
59 memgraph: memgraph.clone(),
60 }
61 }
62}
63
64impl Drop for MapIterator {
65 fn drop(&mut self) {
66 unsafe {
67 if !self.ptr.is_null() {
68 ffi::mgp_map_items_iterator_destroy(self.ptr);
69 }
70 }
71 }
72}
73
74impl Iterator for MapIterator {
75 type Item = MapItem;
76
77 fn next(&mut self) -> Option<MapItem> {
78 unsafe {
79 let data = if self.is_first {
80 self.is_first = false;
81 ffi::mgp_map_items_iterator_get(self.ptr)
82 } else {
83 ffi::mgp_map_items_iterator_next(self.ptr)
84 };
85
86 if data.is_null() {
87 None
88 } else {
89 let mgp_map_item_key = ffi::mgp_map_item_key(data);
90 let mgp_map_item_value = ffi::mgp_map_item_value(data);
91 let key = match create_cstring(mgp_map_item_key) {
92 Ok(v) => v,
93 Err(_) => panic!("Unable to create map item key."),
94 };
95 let value = match mgp_raw_value_to_value(mgp_map_item_value, &self.memgraph) {
96 Ok(v) => v,
97 Err(_) => panic!("Unable to create map item value."),
98 };
99 Some(MapItem { key, value })
100 }
101 }
102 }
103}
104
105impl Map {
106 pub(crate) fn new(ptr: *mut mgp_map, memgraph: &Memgraph) -> Map {
107 #[cfg(not(test))]
108 assert!(
109 !ptr.is_null(),
110 "Unable to create map because the given pointer is null."
111 );
112
113 Map {
114 ptr,
115 memgraph: memgraph.clone(),
116 }
117 }
118
119 pub(crate) unsafe fn mgp_copy(ptr: *const mgp_map, memgraph: &Memgraph) -> MgpResult<Map> {
120 #[cfg(not(test))]
121 assert!(
122 !ptr.is_null(),
123 "Unable to create map copy because the given pointer is null."
124 );
125
126 let mgp_map_copy = ffi::mgp_map_make_empty(memgraph.memory_ptr());
127 let mgp_map_iterator = ffi::mgp_map_iter_items(ptr, memgraph.memory_ptr());
128 if mgp_map_iterator.is_null() {
129 ffi::mgp_map_destroy(mgp_map_copy);
130 return Err(MgpError::UnableToCopyMap);
131 }
132 let map_iterator = MapIterator::new(mgp_map_iterator, &memgraph);
133 for item in map_iterator {
134 let mgp_value = item.value.to_mgp_value(&memgraph)?;
135 if ffi::mgp_map_insert(mgp_map_copy, item.key.as_ptr(), mgp_value.mgp_ptr()) == 0 {
136 ffi::mgp_map_destroy(mgp_map_copy);
137 return Err(MgpError::UnableToCopyMap);
138 }
139 }
140 Ok(Map::new(mgp_map_copy, &memgraph))
141 }
142
143 pub fn make_empty(memgraph: &Memgraph) -> MgpResult<Map> {
144 unsafe {
145 let mgp_ptr = ffi::mgp_map_make_empty(memgraph.memory_ptr());
146 if mgp_ptr.is_null() {
147 return Err(MgpError::UnableToCreateEmptyMap);
148 }
149 Ok(Map::new(mgp_ptr, &memgraph))
150 }
151 }
152
153 pub fn insert(&self, key: &CStr, value: &Value) -> MgpResult<()> {
154 unsafe {
155 let mgp_value = value.to_mgp_value(&self.memgraph)?;
156 if ffi::mgp_map_insert(self.ptr, key.as_ptr(), mgp_value.mgp_ptr()) == 0 {
157 return Err(MgpError::UnableToInsertMapValue);
158 }
159 Ok(())
160 }
161 }
162
163 pub fn size(&self) -> u64 {
164 unsafe { ffi::mgp_map_size(self.ptr) }
165 }
166
167 pub fn at(&self, key: &CStr) -> MgpResult<Value> {
168 unsafe {
169 let c_value = ffi::mgp_map_at(self.ptr, key.as_ptr());
170 if c_value.is_null() {
171 return Err(MgpError::UnableToAccessMapValue);
172 }
173 mgp_raw_value_to_value(c_value, &self.memgraph)
174 }
175 }
176
177 pub fn iter(&self) -> MgpResult<MapIterator> {
178 unsafe {
179 let mgp_iterator = ffi::mgp_map_iter_items(self.ptr, self.memgraph.memory_ptr());
180 if mgp_iterator.is_null() {
181 return Err(MgpError::UnableToCreateMapIterator);
182 }
183 Ok(MapIterator::new(mgp_iterator, &self.memgraph))
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests;