rsmgp_sys/list/
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 list datatype.
15
16use crate::memgraph::*;
17use crate::mgp::*;
18use crate::result::*;
19use crate::value::*;
20// Required here, if not present tests linking fails.
21#[double]
22use crate::mgp::ffi;
23use mockall_double::double;
24
25// NOTE: Not possible to implement [std::iter::IntoIterator] because the [ListIterator] holds the
26// [List] reference which needs the lifetime specifier.
27pub struct List {
28    ptr: *mut mgp_list,
29    memgraph: Memgraph,
30}
31
32impl Drop for List {
33    fn drop(&mut self) {
34        unsafe {
35            if !self.ptr.is_null() {
36                ffi::mgp_list_destroy(self.ptr);
37            }
38        }
39    }
40}
41
42pub struct ListIterator<'a> {
43    list: &'a List,
44    position: u64,
45}
46
47impl<'a> Iterator for ListIterator<'a> {
48    type Item = Value;
49
50    fn next(&mut self) -> Option<Value> {
51        if self.position >= self.list.size() {
52            return None;
53        }
54        let value = match self.list.value_at(self.position) {
55            Ok(v) => v,
56            Err(_) => panic!("Unable to access the next list value."),
57        };
58        self.position += 1;
59        Some(value)
60    }
61}
62
63impl List {
64    pub(crate) fn new(ptr: *mut mgp_list, memgraph: &Memgraph) -> List {
65        #[cfg(not(test))]
66        assert!(
67            !ptr.is_null(),
68            "Unable to create list because the given pointer is null."
69        );
70
71        List {
72            ptr,
73            memgraph: memgraph.clone(),
74        }
75    }
76
77    pub fn make_empty(capacity: u64, memgraph: &Memgraph) -> MgpResult<List> {
78        unsafe {
79            let mgp_ptr = ffi::mgp_list_make_empty(capacity, memgraph.memory_ptr());
80            if mgp_ptr.is_null() {
81                return Err(MgpError::UnableToCreateEmptyList);
82            }
83            Ok(List::new(mgp_ptr, &memgraph))
84        }
85    }
86
87    /// Creates a new List based on [mgp_list].
88    pub(crate) unsafe fn mgp_copy(ptr: *const mgp_list, memgraph: &Memgraph) -> MgpResult<List> {
89        #[cfg(not(test))]
90        assert!(
91            !ptr.is_null(),
92            "Unable to create list copy because the given pointer is null."
93        );
94
95        let size = ffi::mgp_list_size(ptr);
96        let mgp_copy = ffi::mgp_list_make_empty(size, memgraph.memory_ptr());
97        if mgp_copy.is_null() {
98            return Err(MgpError::UnableToCopyList);
99        }
100        for index in 0..size {
101            let mgp_value = ffi::mgp_list_at(ptr, index);
102            if ffi::mgp_list_append(mgp_copy, mgp_value) == 0 {
103                ffi::mgp_list_destroy(mgp_copy);
104                return Err(MgpError::UnableToCopyList);
105            }
106        }
107        Ok(List::new(mgp_copy, &memgraph))
108    }
109
110    pub fn copy(&self) -> MgpResult<List> {
111        unsafe { List::mgp_copy(self.ptr, &self.memgraph) }
112    }
113
114    /// Appends value to the list, but if there is no place, returns an error.
115    pub fn append(&self, value: &Value) -> MgpResult<()> {
116        unsafe {
117            let mgp_value = value.to_mgp_value(&self.memgraph)?;
118            if ffi::mgp_list_append(self.ptr, mgp_value.mgp_ptr()) == 0 {
119                return Err(MgpError::UnableToAppendListValue);
120            }
121            Ok(())
122        }
123    }
124
125    /// In case of a capacity change, the previously contained elements will move in
126    /// memory and any references to them will be invalid.
127    pub fn append_extend(&self, value: &Value) -> MgpResult<()> {
128        unsafe {
129            let mgp_value = value.to_mgp_value(&self.memgraph)?;
130            if ffi::mgp_list_append_extend(self.ptr, mgp_value.mgp_ptr()) == 0 {
131                return Err(MgpError::UnableToAppendExtendListValue);
132            }
133            Ok(())
134        }
135    }
136
137    pub fn size(&self) -> u64 {
138        unsafe { ffi::mgp_list_size(self.ptr) }
139    }
140
141    pub fn capacity(&self) -> u64 {
142        unsafe { ffi::mgp_list_capacity(self.ptr) }
143    }
144
145    /// Always copies the underlying value because in case of the capacity change any references
146    /// would become invalid.
147    pub fn value_at(&self, index: u64) -> MgpResult<Value> {
148        unsafe {
149            let c_value = ffi::mgp_list_at(self.ptr, index);
150            if c_value.is_null() {
151                return Err(MgpError::UnableToAccessListValueByIndex);
152            }
153            mgp_raw_value_to_value(c_value, &self.memgraph)
154        }
155    }
156
157    pub fn iter(&self) -> MgpResult<ListIterator> {
158        Ok(ListIterator {
159            list: self,
160            position: 0,
161        })
162    }
163}
164
165#[cfg(test)]
166mod tests;