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

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new 729f971  [Docs] Add Rust Docs (#160)
729f971 is described below

commit 729f971f272c7a098d032ed80ffcea1aaf580d66
Author: Yixin Dong <[email protected]>
AuthorDate: Sat Oct 18 08:36:03 2025 -0400

    [Docs] Add Rust Docs (#160)
    
    This PR adds Rust API docs and a simple tutorial
    
    The rust docstrings still have space for enhancement. We can add more
    docstrings later.
---
 docs/README.md                |  38 +++++++-
 docs/conf.py                  |  55 ++++++++++-
 docs/guides/rust_guide.md     | 217 ++++++++++++++++++++++++++++++++++++++++++
 docs/index.rst                |   2 +
 docs/reference/rust/index.rst |  40 ++++++++
 rust/tvm-ffi-sys/build.rs     |  38 ++++++--
 6 files changed, 379 insertions(+), 11 deletions(-)

diff --git a/docs/README.md b/docs/README.md
index f0edc73..d790e07 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -56,12 +56,45 @@ sudo apt install doxygen    # Linux
 Set `BUILD_CPP_DOCS=1` on the desired build command to enable the extra step:
 
 ```bash
-# Interactive build
-BUILD_CPP_DOCS=1 uv run --group docs sphinx-autobuild docs docs/_build/html 
--ignore docs/reference/cpp/generated
+# Interactive build with auto-rebuild on C++ header changes
+BUILD_CPP_DOCS=1 uv run --group docs sphinx-autobuild docs docs/_build/html 
--ignore docs/reference/cpp/generated --watch include
 # One-off build
 BUILD_CPP_DOCS=1 uv run --group docs sphinx-build -M html docs docs/_build
 ```
 
+The C++ documentation will automatically rebuild when header files change 
during `sphinx-autobuild` sessions.
+
+### Build with Rust Docs
+
+Generating the Rust reference requires `cargo` to be installed:
+
+```bash
+# Install Rust toolchain if not already installed
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+```
+
+Set `BUILD_RUST_DOCS=1` on the desired build command to enable Rust 
documentation:
+
+```bash
+# Interactive build with auto-rebuild on Rust source changes
+BUILD_RUST_DOCS=1 uv run --group docs sphinx-autobuild docs docs/_build/html 
--ignore docs/reference/rust/generated --watch rust
+# One-off build (clean rebuild)
+BUILD_RUST_DOCS=1 uv run --group docs sphinx-build -M html docs docs/_build
+```
+
+The Rust documentation will automatically rebuild when source files change 
during `sphinx-autobuild` sessions.
+
+### Build All Documentation
+
+To build documentation with all language references enabled:
+
+```bash
+# Interactive build
+BUILD_CPP_DOCS=1 BUILD_RUST_DOCS=1 uv run --group docs sphinx-autobuild docs 
docs/_build/html --ignore docs/reference/cpp/generated --ignore 
docs/reference/rust/generated --watch include --watch rust
+# One-off build
+BUILD_CPP_DOCS=1 BUILD_RUST_DOCS=1 uv run --group docs sphinx-build -M html 
docs docs/_build
+```
+
 ## Cleanup
 
 Remove generated artifacts when they are no longer needed:
@@ -70,4 +103,5 @@ Remove generated artifacts when they are no longer needed:
 rm -rf docs/_build/
 rm -rf docs/reference/python/generated
 rm -rf docs/reference/cpp/generated
+rm -rf docs/reference/rust/generated
 ```
diff --git a/docs/conf.py b/docs/conf.py
index 28f87df..82ec1fb 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -18,6 +18,9 @@
 
 # -*- coding: utf-8 -*-
 import os
+import shutil
+import subprocess
+import sys
 from pathlib import Path
 
 import sphinx
@@ -26,7 +29,15 @@ import tomli
 os.environ["TVM_FFI_BUILD_DOCS"] = "1"
 
 build_exhale = os.environ.get("BUILD_CPP_DOCS", "0") == "1"
+build_rust_docs = os.environ.get("BUILD_RUST_DOCS", "0") == "1"
 
+# Auto-detect sphinx-autobuild: Check if sphinx-autobuild is in the execution 
path
+is_autobuild = any("sphinx-autobuild" in str(arg) for arg in sys.argv)
+
+# -- Path constants -------------------------------------------------------
+_DOCS_DIR = Path(__file__).resolve().parent
+_RUST_DIR = _DOCS_DIR.parent / "rust"
+_RUST_OUTPUT_DIR = _DOCS_DIR / "reference" / "rust" / "generated"
 
 # -- General configuration ------------------------------------------------
 # Load version from pyproject.toml
@@ -90,6 +101,7 @@ This page contains the full API index for the C++ API.
 """
 
 # Setup the exhale extension
+
 exhale_args = {
     "containmentFolder": "reference/cpp/generated",
     "rootFileName": "index.rst",
@@ -151,7 +163,6 @@ autosummary_filename_map = {
     "tvm_ffi.Device": "tvm_ffi.Device_class",
 }
 
-_DOCS_DIR = Path(__file__).resolve().parent
 _STUBS = {
     "_stubs/cpp_index.rst": "reference/cpp/generated/index.rst",
 }
@@ -167,15 +178,53 @@ def _prepare_stub_files() -> None:
             dst_path.write_text(src_path.read_text(encoding="utf-8"), 
encoding="utf-8")
 
 
+def _build_rust_docs() -> None:
+    """Build Rust documentation using cargo doc."""
+    if not build_rust_docs:
+        return
+
+    print("Building Rust documentation...")
+    try:
+        target_doc = _RUST_DIR / "target" / "doc"
+
+        # In auto-reload mode (sphinx-autobuild), keep incremental builds
+        # Otherwise (CI/production), do clean rebuild
+        if not is_autobuild and target_doc.exists():
+            print("Clean rebuild: removing old documentation...")
+            shutil.rmtree(target_doc)
+
+        # Generate documentation (without dependencies)
+        subprocess.run(
+            ["cargo", "doc", "--no-deps", "--workspace", "--target-dir", 
"target"],
+            check=True,
+            cwd=_RUST_DIR,
+            env={**os.environ, "RUSTDOCFLAGS": "--cfg docsrs"},
+        )
+
+        # Copy generated documentation
+        if _RUST_OUTPUT_DIR.exists():
+            shutil.rmtree(_RUST_OUTPUT_DIR)
+        shutil.copytree(target_doc, _RUST_OUTPUT_DIR)
+
+        print(f"Rust documentation built successfully at {_RUST_OUTPUT_DIR}")
+    except subprocess.CalledProcessError as e:
+        print(f"Warning: Failed to build Rust documentation: {e}")
+    except FileNotFoundError:
+        print("Warning: cargo not found, skipping Rust documentation build")
+
+
 def _apply_config_overrides(_: object, config: object) -> None:
     """Apply runtime configuration overrides derived from environment 
variables."""
     config.build_exhale = build_exhale
+    config.build_rust_docs = build_rust_docs
 
 
 def setup(app: sphinx.application.Sphinx) -> None:
     """Register custom Sphinx configuration values."""
     _prepare_stub_files()
+    _build_rust_docs()
     app.add_config_value("build_exhale", build_exhale, "env")
+    app.add_config_value("build_rust_docs", build_rust_docs, "env")
     app.connect("config-inited", _apply_config_overrides)
 
 
@@ -301,4 +350,8 @@ html_context = {
 
 html_static_path = ["_static"]
 
+# Copy Rust documentation to output if enabled
+html_extra_path = ["reference/rust/generated"] if build_rust_docs else []
+
+
 html_css_files = ["custom.css"]
diff --git a/docs/guides/rust_guide.md b/docs/guides/rust_guide.md
new file mode 100644
index 0000000..a1b7ac7
--- /dev/null
+++ b/docs/guides/rust_guide.md
@@ -0,0 +1,217 @@
+<!--- 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. -->
+
+# Rust Guide
+
+```{note}
+The Rust support is currently in an experimental stage.
+```
+
+This guide demonstrates how to use TVM FFI from Rust applications.
+
+## Installation
+
+### Prerequisites
+
+The Rust support depends on `libtvm_ffi`. First, install the `tvm-ffi` Python 
package:
+
+```bash
+pip install -v -e .
+```
+
+Confirm that `tvm-ffi-config` is available:
+
+```bash
+tvm-ffi-config --libdir
+```
+
+### Adding to Your Project
+
+Add to your `Cargo.toml`:
+
+```toml
+[dependencies]
+tvm-ffi = { path = "path/to/tvm-ffi/rust/tvm-ffi" }
+```
+
+For published versions (when available):
+
+```toml
+[dependencies]
+tvm-ffi = "0.1.0-alpha.0"
+```
+
+### Environment Setup
+
+Set the library path so `libtvm_ffi` can be found at runtime:
+
+```bash
+export LD_LIBRARY_PATH=$(tvm-ffi-config --libdir):$LD_LIBRARY_PATH
+```
+
+## Basic Usage
+
+### Loading a Module
+
+Load a compiled TVM FFI module and call its functions:
+
+```rust
+use tvm_ffi::{Module, Result};
+
+fn main() -> Result<()> {
+    // Load compiled module
+    let module = Module::load_from_file("build/add_one_cpu.so")?;
+
+    // Get function by name
+    let add_fn = module.get_function("add_one_cpu")?;
+
+    Ok(())
+}
+```
+
+### Working with Tensors
+
+Create and manipulate tensors:
+
+```rust
+use tvm_ffi::Tensor;
+
+// Create a tensor from a slice
+let data = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0];
+let tensor = Tensor::from_slice(&data, &[2, 3])?;
+```
+
+### Calling Functions
+
+Call functions with tensors:
+
+```rust
+use tvm_ffi::{Module, Tensor, Result};
+
+fn run_example() -> Result<()> {
+    let module = Module::load_from_file("build/add_one_cpu.so")?;
+    let func = module.get_function("add_one_cpu")?;
+
+    // Create input and output tensors
+    let input = Tensor::from_slice(&[1.0f32, 2.0, 3.0, 4.0], &[4])?;
+    let output = Tensor::from_slice(&[0.0f32; 4], &[4])?;
+
+    // Call function
+    func.call_tuple((&input, &output))?;
+
+    Ok(())
+}
+```
+
+## Advanced Topics
+
+### Global Functions
+
+Register and access global functions:
+
+```rust
+use tvm_ffi::Function;
+
+// Get global function
+let func = Function::get_global("my_function")?;
+
+// Register a new global function
+let my_func = Function::from_packed(|args: &[AnyView]| -> Result<Any> {
+    // Function implementation
+    Ok(Any::default())
+});
+Function::register_global("my_custom_func", my_func)?;
+```
+
+### Type-Erased Functions
+
+Create functions from Rust closures:
+
+```rust
+use tvm_ffi::{Function, Any, AnyView, Result};
+
+// From packed closure
+let func = Function::from_packed(|args: &[AnyView]| -> Result<Any> {
+    // Process args and return result
+    Ok(Any::default())
+});
+
+// From typed closure
+let typed_func = Function::from_typed(|x: i64, y: i64| -> Result<i64> {
+    Ok(x + y)
+});
+```
+
+### Error Handling
+
+TVM FFI uses standard Rust `Result` types:
+
+```rust
+use tvm_ffi::{Error, Module, Result, VALUE_ERROR};
+
+fn may_fail(value: i32) -> Result<()> {
+    // Operations that may fail
+    let module = Module::load_from_file("path.so")?;
+
+    // Custom errors
+    if value < 0 {
+        return Err(Error::new(
+            VALUE_ERROR,
+            "Value must be non-negative",
+            ""
+        ));
+    }
+
+    Ok(())
+}
+```
+
+## Examples
+
+The repository includes a complete example in 
`rust/tvm-ffi/examples/load_library.rs`.
+
+Run it with:
+
+```bash
+cd rust
+cargo run --example load_library --features example
+```
+
+## Building the Workspace
+
+Build the entire Rust workspace:
+
+```bash
+cd rust
+cargo build
+```
+
+Run tests:
+
+```bash
+cargo test
+```
+
+## API Reference
+
+For detailed API documentation, see the [Rust API 
Reference](../reference/rust/index.rst).
+
+## Related Resources
+
+- [Quick Start Guide](../get_started/quickstart.rst) - General TVM FFI 
introduction
+- [C++ Guide](cpp_guide.md) - C++ API usage
+- [Python Guide](python_guide.md) - Python API usage
diff --git a/docs/index.rst b/docs/index.rst
index 5e8fd0c..f885799 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -48,6 +48,7 @@ Table of Contents
    guides/python_packaging.md
    guides/cpp_guide.md
    guides/python_guide.md
+   guides/rust_guide.md
    guides/stable_c_abi.md
    guides/compiler_integration.md
    guides/build_from_source.md
@@ -66,3 +67,4 @@ Table of Contents
 
    reference/python/index.rst
    reference/cpp/index.rst
+   reference/rust/index.rst
diff --git a/docs/reference/rust/index.rst b/docs/reference/rust/index.rst
new file mode 100644
index 0000000..12a71be
--- /dev/null
+++ b/docs/reference/rust/index.rst
@@ -0,0 +1,40 @@
+..  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.
+
+Rust API
+========
+
+This page contains the API reference for the Rust API. The tvm-ffi project 
provides
+Rust bindings that allow you to use the TVM FFI from Rust programs.
+
+Crates
+------
+
+The Rust API is organized into three crates:
+
+.. list-table::
+   :header-rows: 1
+   :widths: 30 70
+
+   * - Crate
+     - Description
+   * - 📦 `tvm-ffi <generated/tvm_ffi/index.html>`_
+     - High-level Rust bindings with safe abstractions for FFI objects, 
functions, tensors, and containers.
+   * - 📦 `tvm-ffi-sys <generated/tvm_ffi_sys/index.html>`_
+     - Low-level unsafe bindings to the C API.
+   * - 📦 `tvm-ffi-macros <generated/tvm_ffi_macros/index.html>`_
+     - Procedural macros for deriving Object and ObjectRef traits.
diff --git a/rust/tvm-ffi-sys/build.rs b/rust/tvm-ffi-sys/build.rs
index 7cd7f24..1f2e64a 100644
--- a/rust/tvm-ffi-sys/build.rs
+++ b/rust/tvm-ffi-sys/build.rs
@@ -47,15 +47,37 @@ fn update_ld_library_path(lib_dir: &str) {
 }
 
 fn main() {
+    // When building documentation, we may not need actual linking
+    // Check if this is a rustdoc build
+    let is_rustdoc = env::var("RUSTDOC").is_ok() || 
env::var("CARGO_CFG_DOC").is_ok();
+
     // Run `mylib-config --libdir` to get the library path
-    let config_output = Command::new("tvm-ffi-config")
-        .arg("--libdir")
-        .output()
-        .expect("Failed to run tvm-ffi-config");
-    let lib_dir = String::from_utf8(config_output.stdout)
-        .expect("Invalid UTF-8 output from tvm-ffi-config")
-        .trim()
-        .to_string();
+    let config_result = 
Command::new("tvm-ffi-config").arg("--libdir").output();
+
+    let lib_dir = match config_result {
+        Ok(output) if output.status.success() => 
String::from_utf8(output.stdout)
+            .unwrap_or_default()
+            .trim()
+            .to_string(),
+        _ if is_rustdoc => {
+            // For rustdoc builds, we can proceed without the library
+            eprintln!("Warning: tvm-ffi-config not available, skipping for 
documentation build");
+            return;
+        }
+        _ => {
+            panic!("Failed to run tvm-ffi-config. Make sure tvm-ffi is 
installed.");
+        }
+    };
+
+    if lib_dir.is_empty() {
+        if is_rustdoc {
+            eprintln!(
+                "Warning: Empty lib_dir from tvm-ffi-config, skipping for 
documentation build"
+            );
+            return;
+        }
+        panic!("tvm-ffi-config returned empty library path");
+    }
 
     // add the library directory to the linker search path
     println!("cargo:rustc-link-search=native={}", lib_dir);

Reply via email to