1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use crate::bindings_to_graphblas_implementation::{
    GrB_Vector_extractTuples_BOOL, GrB_Vector_extractTuples_FP32, GrB_Vector_extractTuples_FP64,
    GrB_Vector_extractTuples_INT16, GrB_Vector_extractTuples_INT32, GrB_Vector_extractTuples_INT64,
    GrB_Vector_extractTuples_INT8, GrB_Vector_extractTuples_UINT16,
    GrB_Vector_extractTuples_UINT32, GrB_Vector_extractTuples_UINT64,
    GrB_Vector_extractTuples_UINT8,
};
use crate::collections::collection::Collection;
use crate::collections::sparse_vector::sparse_vector::GraphblasSparseVectorTrait;
use crate::collections::sparse_vector::SparseVector;
use crate::context::CallGraphBlasContext;
use crate::context::ContextTrait;
use crate::error::GraphblasError;
use crate::error::GraphblasErrorType;
use crate::index::ElementIndex;
use crate::index::IndexConversion;
use crate::value_type::ConvertVector;
use crate::{
    collections::sparse_vector::VectorElementList,
    error::SparseLinearAlgebraError,
    value_type::{
        utilities_to_implement_traits_for_all_value_types::implement_1_type_macro_for_all_value_types_and_typed_graphblas_function_with_implementation_type,
        ValueType,
    },
};
use suitesparse_graphblas_sys::GrB_Index;

pub trait GetVectorElementList<T: ValueType> {
    fn get_element_list(&self) -> Result<VectorElementList<T>, SparseLinearAlgebraError>;
}

impl<T: ValueType + GetGraphblasVectorElementList<T>> GetVectorElementList<T> for SparseVector<T> {
    fn get_element_list(&self) -> Result<VectorElementList<T>, SparseLinearAlgebraError> {
        T::get_element_list(self)
    }
}

pub trait GetGraphblasVectorElementList<T: ValueType> {
    fn get_element_list(
        vector: &SparseVector<T>,
    ) -> Result<VectorElementList<T>, SparseLinearAlgebraError>;
}

macro_rules! implement_get_element_list {
    ($value_type:ty, $graphblas_implementation_type:ty, $get_element_function:ident) => {
        impl GetGraphblasVectorElementList<$value_type> for $value_type {
            fn get_element_list(
                vector: &SparseVector<$value_type>,
            ) -> Result<VectorElementList<$value_type>, SparseLinearAlgebraError> {
                let number_of_stored_elements = vector.number_of_stored_elements()?;

                let mut graphblas_indices: Vec<GrB_Index> = Vec::with_capacity(number_of_stored_elements);
                let mut values: Vec<$graphblas_implementation_type> = Vec::with_capacity(number_of_stored_elements);

                let mut number_of_stored_and_returned_elements = number_of_stored_elements.as_graphblas_index()?;

                vector.context_ref().call(|| unsafe {
                    $get_element_function(
                        graphblas_indices.as_mut_ptr(),
                        values.as_mut_ptr(),
                        &mut number_of_stored_and_returned_elements,
                        vector.graphblas_vector())
                }, unsafe{ &vector.graphblas_vector() })?;

                let length_of_element_list = ElementIndex::from_graphblas_index(number_of_stored_and_returned_elements)?;

                unsafe {
                    if length_of_element_list == number_of_stored_elements {
                        graphblas_indices.set_len(length_of_element_list);
                        values.set_len(length_of_element_list);
                    } else {
                        let err: SparseLinearAlgebraError = GraphblasError::new(GraphblasErrorType::IndexOutOfBounds,
                            format!("matrix.number_of_stored_elements {} unequal to length of returned values {}",number_of_stored_elements, length_of_element_list)).into();
                        return Err(err)
                    }
                };

                let mut indices: Vec<ElementIndex> = Vec::with_capacity(length_of_element_list);

                for index in graphblas_indices.into_iter() {
                    indices.push(ElementIndex::from_graphblas_index(index)?);
                }

                let values = ConvertVector::<$graphblas_implementation_type, $value_type>::to_type(values)?;
                let element_list = VectorElementList::from_vectors(indices, values)?;
                Ok(element_list)
            }
        }
    };
}

implement_1_type_macro_for_all_value_types_and_typed_graphblas_function_with_implementation_type!(
    implement_get_element_list,
    GrB_Vector_extractTuples
);