This is an automated email from the ASF dual-hosted git repository.

xiaokang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-graphar.git


The following commit(s) were added to refs/heads/main by this push:
     new 76b5163e feat(Rust): add DataType support (#822)
76b5163e is described below

commit 76b5163e47bda7d20d8547d9aa0c79255a8b4541
Author: Jinye Wu <[email protected]>
AuthorDate: Sun Jan 11 18:19:56 2026 +0800

    feat(Rust): add DataType support (#822)
    
    * support `Type` and `DataType`
    
    * add rust ci
    
    * add license
    
    * add comments in rust/build.rs
    
    * update CI and build.rs
    
    * fix potential error
    
    * add docs
---
 .github/workflows/rust.yaml |  12 +-
 rust/build.rs               |   6 +-
 rust/include/graphar_rs.h   |   9 +-
 rust/src/ffi.rs             |  72 +++++++++--
 rust/src/graphar_rs.cc      |   9 +-
 rust/src/lib.rs             |   5 +
 rust/src/types.rs           | 297 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 389 insertions(+), 21 deletions(-)

diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml
index 26c16e52..76e135d7 100644
--- a/.github/workflows/rust.yaml
+++ b/.github/workflows/rust.yaml
@@ -70,7 +70,7 @@ jobs:
         uses: taiki-e/install-action@v2
         with:
           tool: [email protected]
-          
+
       - name: Install cargo-machete
         uses: taiki-e/install-action@v2
         with:
@@ -138,6 +138,16 @@ jobs:
           cargo test --doc
         timeout-minutes: 30
 
+      - name: Release Build
+        run: cargo build -r
+        timeout-minutes: 30
+
+      - name: Release Test
+        run: |
+          cargo nextest run -r
+          cargo test -r --doc
+        timeout-minutes: 30
+
       - name: Build Docs
         run: cargo doc --lib --no-deps
         timeout-minutes: 30
diff --git a/rust/build.rs b/rust/build.rs
index b8cefe46..73542f84 100644
--- a/rust/build.rs
+++ b/rust/build.rs
@@ -16,11 +16,12 @@
 // under the License.
 
 // Portions adapted from 
`https://github.com/kuzudb/kuzu/blob/master/tools/rust_api/build.rs` (MIT 
License).
+
 use std::env;
 use std::path::{Path, PathBuf};
 
 fn link_libraries() {
-    // Link to system Arrow, `libarrow` is under `/usr/lib/x86_64-linux-gnu/` 
on Ubuntu
+    // TODO: Link to system Arrow, `libarrow` is under 
`/usr/lib/x86_64-linux-gnu/` on Ubuntu
     println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/");
     println!("cargo:rustc-link-lib=dylib=arrow_compute");
     println!("cargo:rustc-link-lib=dylib=arrow_dataset");
@@ -60,7 +61,8 @@ fn build_graphar() -> Vec<PathBuf> {
     build
         .no_build_target(true)
         .define("CMAKE_BUILD_TYPE", cmake_build_type)
-        .define("GRAPHAR_BUILD_STATIC", "on");
+        .define("GRAPHAR_BUILD_STATIC", "ON")
+        .define("GRAPHAR_ENABLE_SANITIZER", "OFF");
     let build_dir = build.build();
 
     let lib_path = build_dir.join("build");
diff --git a/rust/include/graphar_rs.h b/rust/include/graphar_rs.h
index b688104c..e654c7ea 100644
--- a/rust/include/graphar_rs.h
+++ b/rust/include/graphar_rs.h
@@ -19,7 +19,10 @@
 
 #pragma once
 
-#include <cstdint>
+#include "graphar/fwd.h"
+#include "graphar/types.h"
+#include "rust/cxx.h"
+
 namespace graphar_rs {
-int64_t foo(int64_t x, int64_t y);
-} // namespace graphar_rs
+rust::String to_type_name(const graphar::DataType &type);
+}
\ No newline at end of file
diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs
index 173b2150..a6ffe000 100644
--- a/rust/src/ffi.rs
+++ b/rust/src/ffi.rs
@@ -17,21 +17,71 @@
 
 #[cxx::bridge(namespace = "graphar")]
 pub(crate) mod graphar {
-    unsafe extern "C++" {
+    extern "C++" {
         include!("graphar_rs.h");
+    }
 
-        #[allow(unused)]
-        #[namespace = "graphar_rs"]
-        fn foo(x: i64, y: i64) -> i64;
+    /// The main data type enumeration used by GraphAr.
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+    #[repr(u32)]
+    enum Type {
+        /// Boolean.
+        #[cxx_name = "BOOL"]
+        Bool = 0,
+        /// Signed 32-bit integer.
+        #[cxx_name = "INT32"]
+        Int32,
+        /// Signed 64-bit integer.
+        #[cxx_name = "INT64"]
+        Int64,
+        /// 4-byte floating point value.
+        #[cxx_name = "FLOAT"]
+        Float,
+        /// 8-byte floating point value.
+        #[cxx_name = "DOUBLE"]
+        Double,
+        /// UTF-8 variable-length string.
+        #[cxx_name = "STRING"]
+        String,
+        /// List of some logical data type.
+        #[cxx_name = "LIST"]
+        List,
+        /// int32 days since the UNIX epoch.
+        #[cxx_name = "DATE"]
+        Date,
+        /// Exact timestamp encoded with int64 since UNIX epoch in 
milliseconds.
+        #[cxx_name = "TIMESTAMP"]
+        Timestamp,
+        /// User-defined data type.
+        #[cxx_name = "USER_DEFINED"]
+        UserDefined,
+        /// Sentinel value; do not use as a real type.
+        #[cxx_name = "MAX_ID"]
+        MaxId,
     }
-}
+    // C++ Enum
+    unsafe extern "C++" {
+        type Type;
+    }
+
+    // `DataType`
+    unsafe extern "C++" {
+        type DataType;
 
-#[cfg(test)]
-mod tests {
-    use super::*;
+        fn Equals(&self, other: &DataType) -> bool;
+        fn value_type(&self) -> &SharedPtr<DataType>;
+        fn id(&self) -> Type;
+        #[namespace = "graphar_rs"]
+        fn to_type_name(data_type: &DataType) -> String;
 
-    #[test]
-    fn test_foo() {
-        assert_eq!(graphar::foo(1, 2), 3);
+        fn int32() -> &'static SharedPtr<DataType>;
+        fn boolean() -> &'static SharedPtr<DataType>;
+        fn int64() -> &'static SharedPtr<DataType>;
+        fn float32() -> &'static SharedPtr<DataType>;
+        fn float64() -> &'static SharedPtr<DataType>;
+        fn string() -> &'static SharedPtr<DataType>;
+        fn date() -> &'static SharedPtr<DataType>;
+        fn timestamp() -> &'static SharedPtr<DataType>;
+        fn list(inner: &SharedPtr<DataType>) -> SharedPtr<DataType>;
     }
 }
diff --git a/rust/src/graphar_rs.cc b/rust/src/graphar_rs.cc
index 2101dc47..88cdf6f9 100644
--- a/rust/src/graphar_rs.cc
+++ b/rust/src/graphar_rs.cc
@@ -18,8 +18,9 @@
  */
 
 #include "graphar_rs.h"
-namespace graphar_rs {
-
-int64_t foo(int64_t x, int64_t y) { return x + y; }
 
-} // namespace graphar_rs
+namespace graphar_rs {
+rust::String to_type_name(const graphar::DataType &type) {
+  return rust::String(type.ToTypeName());
+}
+} // namespace graphar_rs
\ No newline at end of file
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 2795c73c..e26e72c9 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -15,4 +15,9 @@
 // specific language governing permissions and limitations
 // under the License.
 
+//! Rust bindings for GraphAr data types.
+
 mod ffi;
+
+/// GraphAr logical data types.
+pub mod types;
diff --git a/rust/src/types.rs b/rust/src/types.rs
new file mode 100644
index 00000000..826cec7d
--- /dev/null
+++ b/rust/src/types.rs
@@ -0,0 +1,297 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! GraphAr logical data types.
+//!
+//! This module provides Rust wrappers around GraphAr's C++ `graphar::DataType`
+//! and `graphar::Type`.
+
+use crate::ffi;
+use cxx::SharedPtr;
+use std::fmt::{Debug, Display};
+
+// C++ enums
+/// The main data type enumeration used by GraphAr.
+///
+/// This is a re-export of the C++ `graphar::Type` enum.
+pub use crate::ffi::graphar::Type;
+
+#[derive(Clone)]
+/// A logical data type used by GraphAr.
+///
+/// This is a thin wrapper around the C++ `graphar::DataType` (held by a
+/// `cxx::SharedPtr`).
+///
+/// Note that `DataType` may be a null pointer. A null `DataType` is used as a
+/// sentinel value (e.g. `value_type()` for non-list types) and formats as
+/// `"null"` via [`Display`] and [`Debug`].
+pub struct DataType(SharedPtr<ffi::graphar::DataType>);
+
+impl PartialEq for DataType {
+    fn eq(&self, other: &Self) -> bool {
+        if self.0.is_null() && other.0.is_null() {
+            return true;
+        }
+        if self.0.is_null() || other.0.is_null() {
+            return false;
+        }
+
+        self.0.Equals(&other.0)
+    }
+}
+
+impl Eq for DataType {}
+
+impl DataType {
+    fn fmt_type_name(&self, f: &mut std::fmt::Formatter<'_>) -> 
std::fmt::Result {
+        match self.0.as_ref() {
+            None => write!(f, "null"),
+            Some(data_type) => write!(f, "{}", 
ffi::graphar::to_type_name(data_type)),
+        }
+    }
+}
+
+impl Display for DataType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.fmt_type_name(f)
+    }
+}
+
+impl Debug for DataType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.fmt_type_name(f)
+    }
+}
+
+impl DataType {
+    /// Returns the element type of a list.
+    ///
+    /// For non-list types, this returns a null `DataType`.
+    pub fn value_type(&self) -> Self {
+        DataType(self.0.value_type().clone())
+    }
+
+    /// Returns the type category of this `DataType`.
+    pub fn id(&self) -> Type {
+        self.0.id()
+    }
+
+    /// Returns the boolean type.
+    pub fn bool() -> Self {
+        Self(ffi::graphar::boolean().clone())
+    }
+
+    /// Returns the signed 32-bit integer type.
+    pub fn int32() -> Self {
+        Self(ffi::graphar::int32().clone())
+    }
+
+    /// Returns the signed 64-bit integer type.
+    pub fn int64() -> Self {
+        Self(ffi::graphar::int64().clone())
+    }
+
+    /// Returns the 32-bit floating point type.
+    pub fn float32() -> Self {
+        Self(ffi::graphar::float32().clone())
+    }
+
+    /// Returns the 64-bit floating point type.
+    pub fn float64() -> Self {
+        Self(ffi::graphar::float64().clone())
+    }
+
+    /// Returns the UTF-8 string type.
+    pub fn string() -> Self {
+        Self(ffi::graphar::string().clone())
+    }
+
+    /// Returns the date type.
+    ///
+    /// This corresponds to `int32` days since the UNIX epoch.
+    pub fn date() -> Self {
+        Self(ffi::graphar::date().clone())
+    }
+
+    /// Returns the timestamp type.
+    ///
+    /// This corresponds to an `int64` number of milliseconds since the UNIX
+    /// epoch.
+    pub fn timestamp() -> Self {
+        Self(ffi::graphar::timestamp().clone())
+    }
+
+    /// Returns a list type whose element type is `value_type`.
+    ///
+    /// # Panics
+    ///
+    /// This method may panic or fail in the underlying C++ implementation if
+    /// `value_type` is a null `DataType`.
+    pub fn list(value_type: &DataType) -> Self {
+        Self(ffi::graphar::list(&value_type.0))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    impl DataType {
+        fn null() -> Self {
+            Self(SharedPtr::null())
+        }
+    }
+
+    // `DataType`
+    #[test]
+    fn test_data_type_equality() {
+        let float = DataType::float32();
+        let float1 = DataType::float32();
+        assert_eq!(float, float1);
+        assert_ne!(DataType::null(), float);
+
+        let double = DataType::float64();
+        assert_ne!(float, double);
+
+        let list_of_float_1 = DataType::list(&float);
+        let list_of_float_2 = DataType::list(&float);
+        assert_eq!(list_of_float_1, list_of_float_2);
+
+        let list_of_double = DataType::list(&double);
+        assert_ne!(list_of_float_1, list_of_double);
+    }
+
+    #[test]
+    fn test_data_type_display_and_debug() {
+        let bool_type = DataType::bool();
+        assert_eq!(format!("{}", bool_type), "bool");
+        assert_eq!(format!("{:?}", bool_type), "bool");
+
+        let int32 = DataType::int32();
+        assert_eq!(format!("{}", int32), "int32");
+        assert_eq!(format!("{:?}", int32), "int32");
+
+        let int64 = DataType::int64();
+        assert_eq!(format!("{}", int64), "int64");
+        assert_eq!(format!("{:?}", int64), "int64");
+
+        let float32 = DataType::float32();
+        assert_eq!(format!("{}", float32), "float");
+        assert_eq!(format!("{:?}", float32), "float");
+
+        let float64 = DataType::float64();
+        assert_eq!(format!("{}", float64), "double");
+        assert_eq!(format!("{:?}", float64), "double");
+
+        let string = DataType::string();
+        assert_eq!(format!("{}", string), "string");
+        assert_eq!(format!("{:?}", string), "string");
+
+        let date = DataType::date();
+        assert_eq!(format!("{}", date), "date");
+        assert_eq!(format!("{:?}", date), "date");
+
+        let timestamp = DataType::timestamp();
+        assert_eq!(format!("{}", timestamp), "timestamp");
+        assert_eq!(format!("{:?}", timestamp), "timestamp");
+
+        let list_of_int32 = DataType::list(&int32);
+        assert_eq!(format!("{}", list_of_int32), "list<int32>");
+        assert_eq!(format!("{:?}", list_of_int32), "list<int32>");
+
+        let nested_list = DataType::list(&list_of_int32);
+        assert_eq!(format!("{}", nested_list), "list<list<int32>>");
+        assert_eq!(format!("{:?}", nested_list), "list<list<int32>>");
+
+        assert_eq!(format!("{}", int32.value_type()), "null");
+        assert_eq!(format!("{:?}", int32.value_type()), "null");
+    }
+
+    #[test]
+    fn test_data_type_value_type() {
+        let bool_type = DataType::bool();
+        assert_eq!(bool_type.value_type(), DataType::null());
+
+        let int32 = DataType::int32();
+        assert_eq!(int32.value_type(), DataType::null());
+
+        let int64 = DataType::int64();
+        assert_eq!(int64.value_type(), DataType::null());
+
+        let float32 = DataType::float32();
+        assert_eq!(float32.value_type(), DataType::null());
+
+        let float64 = DataType::float64();
+        assert_eq!(float64.value_type(), DataType::null());
+
+        let string = DataType::string();
+        assert_eq!(string.value_type(), DataType::null());
+
+        let date = DataType::date();
+        assert_eq!(date.value_type(), DataType::null());
+
+        let timestamp = DataType::timestamp();
+        assert_eq!(timestamp.value_type(), DataType::null());
+
+        let list_of_int32 = DataType::list(&int32);
+        assert_eq!(list_of_int32.value_type(), int32);
+
+        let list_of_float32 = DataType::list(&float32);
+        assert_eq!(list_of_float32.value_type(), float32);
+
+        let list_of_string = DataType::list(&string);
+        assert_eq!(list_of_string.value_type(), string);
+
+        let nested_list = DataType::list(&list_of_int32);
+        assert_eq!(nested_list.value_type(), list_of_int32);
+    }
+
+    #[test]
+    fn test_data_type_id() {
+        let bool_type = DataType::bool();
+        assert_eq!(bool_type.id(), Type::Bool);
+
+        let int32 = DataType::int32();
+        assert_eq!(int32.id(), Type::Int32);
+
+        let int64 = DataType::int64();
+        assert_eq!(int64.id(), Type::Int64);
+
+        let float32 = DataType::float32();
+        assert_eq!(float32.id(), Type::Float);
+
+        let float64 = DataType::float64();
+        assert_eq!(float64.id(), Type::Double);
+
+        let string = DataType::string();
+        assert_eq!(string.id(), Type::String);
+
+        let date = DataType::date();
+        assert_eq!(date.id(), Type::Date);
+
+        let timestamp = DataType::timestamp();
+        assert_eq!(timestamp.id(), Type::Timestamp);
+
+        let list_of_int32 = DataType::list(&int32);
+        assert_eq!(list_of_int32.id(), Type::List);
+        assert_eq!(list_of_int32.value_type().id(), Type::Int32);
+
+        let list_of_lists = DataType::list(&list_of_int32);
+        assert_eq!(list_of_lists.id(), Type::List);
+        assert_eq!(list_of_lists.value_type().id(), Type::List);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to