use std::convert::From;
use std::ffi::{CStr, CString};
use crate::edge::*;
use crate::list::*;
use crate::map::*;
use crate::memgraph::*;
use crate::mgp::*;
use crate::path::*;
use crate::result::*;
use crate::vertex::*;
#[double]
use crate::mgp::ffi;
use mockall_double::double;
pub(crate) unsafe fn create_cstring(c_char_ptr: *const i8) -> MgpResult<CString> {
match CString::new(CStr::from_ptr(c_char_ptr).to_bytes()) {
Ok(v) => Ok(v),
Err(_) => Err(MgpError::UnableToCreateCString),
}
}
pub struct MgpValue {
ptr: *mut mgp_value,
memgraph: Memgraph,
}
impl Drop for MgpValue {
fn drop(&mut self) {
unsafe {
if !self.ptr.is_null() {
ffi::mgp_value_destroy(self.ptr);
}
}
}
}
impl MgpValue {
pub(crate) fn new(ptr: *mut mgp_value, memgraph: &Memgraph) -> MgpValue {
#[cfg(not(test))]
assert!(
!ptr.is_null(),
"Unable to create Memgraph value because the given pointer is null."
);
MgpValue {
ptr,
memgraph: memgraph.clone(),
}
}
pub(crate) fn mgp_ptr(&self) -> *const mgp_value {
self.ptr
}
pub fn to_value(&self) -> MgpResult<Value> {
unsafe { mgp_raw_value_to_value(self.mgp_ptr(), &self.memgraph) }
}
pub fn make_null(memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_ptr = ffi::mgp_value_make_null(memgraph.memory_ptr());
if mgp_ptr.is_null() {
return Err(MgpError::UnableToMakeNullValue);
}
Ok(MgpValue::new(mgp_ptr, &memgraph))
}
}
pub fn is_null(&self) -> bool {
unsafe { ffi::mgp_value_is_null(self.ptr) != 0 }
}
pub fn make_bool(value: bool, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_ptr =
ffi::mgp_value_make_bool(if !value { 0 } else { 1 }, memgraph.memory_ptr());
if mgp_ptr.is_null() {
return Err(MgpError::UnableToMakeBoolValue);
}
Ok(MgpValue::new(mgp_ptr, &memgraph))
}
}
pub fn is_bool(&self) -> bool {
unsafe { ffi::mgp_value_is_bool(self.ptr) != 0 }
}
pub fn make_int(value: i64, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_ptr = ffi::mgp_value_make_int(value, memgraph.memory_ptr());
if mgp_ptr.is_null() {
return Err(MgpError::UnableToMakeIntegerValue);
}
Ok(MgpValue::new(mgp_ptr, &memgraph))
}
}
pub fn is_int(&self) -> bool {
unsafe { ffi::mgp_value_is_int(self.ptr) != 0 }
}
pub fn make_double(value: f64, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_ptr = ffi::mgp_value_make_double(value, memgraph.memory_ptr());
if mgp_ptr.is_null() {
return Err(MgpError::UnableToMakeDoubleValue);
}
Ok(MgpValue::new(mgp_ptr, &memgraph))
}
}
pub fn is_double(&self) -> bool {
unsafe { ffi::mgp_value_is_double(self.ptr) != 0 }
}
pub fn make_string(value: &CStr, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_ptr = ffi::mgp_value_make_string(value.as_ptr(), memgraph.memory_ptr());
if mgp_ptr.is_null() {
return Err(MgpError::UnableToMakeMemgraphStringValue);
}
Ok(MgpValue::new(mgp_ptr, &memgraph))
}
}
pub fn is_string(&self) -> bool {
unsafe { ffi::mgp_value_is_string(self.ptr) != 0 }
}
pub fn make_list(list: &List, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_list = ffi::mgp_list_make_empty(list.size(), memgraph.memory_ptr());
for item in list.iter()? {
let mgp_value = item.to_mgp_value(&memgraph)?;
if ffi::mgp_list_append(mgp_list, mgp_value.ptr) == 0 {
ffi::mgp_list_destroy(mgp_list);
return Err(MgpError::UnableToMakeListValue);
}
}
let mgp_value = ffi::mgp_value_make_list(mgp_list);
if mgp_value.is_null() {
ffi::mgp_list_destroy(mgp_list);
return Err(MgpError::UnableToMakeListValue);
}
Ok(MgpValue::new(mgp_value, &memgraph))
}
}
pub fn is_list(&self) -> bool {
unsafe { ffi::mgp_value_is_list(self.ptr) != 0 }
}
pub fn make_map(map: &Map, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_map = ffi::mgp_map_make_empty(memgraph.memory_ptr());
for item in map.iter()? {
let mgp_value = match item.value.to_mgp_value(&memgraph) {
Ok(v) => v,
Err(_) => {
ffi::mgp_map_destroy(mgp_map);
return Err(MgpError::UnableToMakeMapValue);
}
};
if ffi::mgp_map_insert(mgp_map, item.key.as_ptr(), mgp_value.ptr) == 0 {
ffi::mgp_map_destroy(mgp_map);
return Err(MgpError::UnableToMakeMapValue);
}
}
let mgp_value = ffi::mgp_value_make_map(mgp_map);
if mgp_value.is_null() {
ffi::mgp_map_destroy(mgp_map);
return Err(MgpError::UnableToMakeMapValue);
}
Ok(MgpValue::new(mgp_value, &memgraph))
}
}
pub fn is_map(&self) -> bool {
unsafe { ffi::mgp_value_is_map(self.ptr) != 0 }
}
pub fn make_vertex(vertex: &Vertex, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_copy = ffi::mgp_vertex_copy(vertex.mgp_ptr(), memgraph.memory_ptr());
if mgp_copy.is_null() {
return Err(MgpError::UnableToMakeVertexValue);
}
let mgp_value = ffi::mgp_value_make_vertex(mgp_copy);
if mgp_value.is_null() {
ffi::mgp_vertex_destroy(mgp_copy);
return Err(MgpError::UnableToMakeVertexValue);
}
Ok(MgpValue::new(mgp_value, &memgraph))
}
}
pub fn is_vertex(&self) -> bool {
unsafe { ffi::mgp_value_is_vertex(self.ptr) != 0 }
}
pub fn make_edge(edge: &Edge, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_copy = ffi::mgp_edge_copy(edge.mgp_ptr(), memgraph.memory_ptr());
if mgp_copy.is_null() {
return Err(MgpError::UnableToMakeEdgeValue);
}
let mgp_value = ffi::mgp_value_make_edge(mgp_copy);
if mgp_value.is_null() {
ffi::mgp_edge_destroy(mgp_copy);
return Err(MgpError::UnableToMakeEdgeValue);
}
Ok(MgpValue::new(mgp_value, &memgraph))
}
}
pub fn is_edge(&self) -> bool {
unsafe { ffi::mgp_value_is_edge(self.ptr) != 0 }
}
pub fn make_path(path: &Path, memgraph: &Memgraph) -> MgpResult<MgpValue> {
unsafe {
let mgp_copy = ffi::mgp_path_copy(path.mgp_ptr(), memgraph.memory_ptr());
if mgp_copy.is_null() {
return Err(MgpError::UnableToMakePathValue);
}
let mgp_value = ffi::mgp_value_make_path(mgp_copy);
if mgp_value.is_null() {
ffi::mgp_path_destroy(mgp_copy);
return Err(MgpError::UnableToMakePathValue);
}
Ok(MgpValue::new(mgp_value, &memgraph))
}
}
pub fn is_path(&self) -> bool {
unsafe { ffi::mgp_value_is_path(self.ptr) != 0 }
}
}
pub enum Value {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(CString),
Vertex(Vertex),
Edge(Edge),
Path(Path),
List(List),
Map(Map),
}
impl Value {
pub fn to_mgp_value(&self, memgraph: &Memgraph) -> MgpResult<MgpValue> {
match self {
Value::Null => MgpValue::make_null(&memgraph),
Value::Bool(x) => MgpValue::make_bool(*x, &memgraph),
Value::Int(x) => MgpValue::make_int(*x, &memgraph),
Value::Float(x) => MgpValue::make_double(*x, &memgraph),
Value::String(x) => MgpValue::make_string(&*x.as_c_str(), &memgraph),
Value::List(x) => MgpValue::make_list(&x, &memgraph),
Value::Map(x) => MgpValue::make_map(&x, &memgraph),
Value::Vertex(x) => MgpValue::make_vertex(&x, &memgraph),
Value::Edge(x) => MgpValue::make_edge(&x, &memgraph),
Value::Path(x) => MgpValue::make_path(&x, &memgraph),
}
}
}
impl From<MgpValue> for Value {
fn from(item: MgpValue) -> Self {
match item.to_value() {
Ok(v) => v,
Err(_) => panic!("Unable to create Value from MgpValue."),
}
}
}
pub(crate) unsafe fn mgp_raw_value_to_value(
value: *const mgp_value,
memgraph: &Memgraph,
) -> MgpResult<Value> {
#[allow(non_upper_case_globals)]
match ffi::mgp_value_get_type(value) {
mgp_value_type_MGP_VALUE_TYPE_NULL => Ok(Value::Null),
mgp_value_type_MGP_VALUE_TYPE_BOOL => Ok(Value::Bool(ffi::mgp_value_get_bool(value) == 0)),
mgp_value_type_MGP_VALUE_TYPE_INT => Ok(Value::Int(ffi::mgp_value_get_int(value))),
mgp_value_type_MGP_VALUE_TYPE_STRING => {
let mgp_string = ffi::mgp_value_get_string(value);
match create_cstring(mgp_string) {
Ok(value) => Ok(Value::String(value)),
Err(_) => Err(MgpError::UnableToMakeValueString),
}
}
mgp_value_type_MGP_VALUE_TYPE_DOUBLE => Ok(Value::Float(ffi::mgp_value_get_double(value))),
mgp_value_type_MGP_VALUE_TYPE_VERTEX => {
let mgp_vertex = ffi::mgp_value_get_vertex(value);
Ok(Value::Vertex(Vertex::mgp_copy(mgp_vertex, &memgraph)?))
}
mgp_value_type_MGP_VALUE_TYPE_EDGE => {
let mgp_edge = ffi::mgp_value_get_edge(value);
Ok(Value::Edge(Edge::mgp_copy(mgp_edge, &memgraph)?))
}
mgp_value_type_MGP_VALUE_TYPE_PATH => {
let mgp_path = ffi::mgp_value_get_path(value);
Ok(Value::Path(Path::mgp_copy(mgp_path, &memgraph)?))
}
mgp_value_type_MGP_VALUE_TYPE_LIST => {
let mgp_list = ffi::mgp_value_get_list(value);
Ok(Value::List(List::mgp_copy(mgp_list, &memgraph)?))
}
mgp_value_type_MGP_VALUE_TYPE_MAP => {
let mgp_map = ffi::mgp_value_get_map(value);
Ok(Value::Map(Map::mgp_copy(mgp_map, &memgraph)?))
}
_ => {
panic!("Unable to create value object because of uncovered mgp_value type.");
}
}
}
#[cfg(test)]
mod tests;