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]