rsmgp_sys/map/
mod.rs

1// Copyright (c) 2016-2021 Memgraph Ltd. [https://memgraph.com]
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! All related to the map (dictionary) datatype.
15
16use std::ffi::{CStr, CString};
17
18use crate::memgraph::*;
19use crate::mgp::*;
20use crate::result::*;
21use crate::value::*;
22// Required here, if not present tests linking fails.
23#[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
42/// [MapItem] has public fields because they are user facing object + they are easier to access.
43pub 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;